You don't know javascript(1)

chapter One 作用域

LHS 为其赋值
RHS 使用该变量
LHS时,如果找不到该变量,则会创建新的全局变量
严格模式下禁止此行为,会抛出ReferrenceError

chapter Two 词法作用域

eval 改变作用域
with 将一个对象的引用当做作用域来处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function foo(obj){
with(obj){
a = 2;
var c = 4;
}
console.log(c)
}
var o1 = {
a:3
}
var o2 = {
b:3
}
foo(o1)
console.log(o1.a)//2
foo(o2)
console.log(o2)//{b:3}
console.log(o2.a)//undefined
console.log(a)//2

对o2执行foo时,在foo上没有找到a属性,往上也没找到,因此创建一个全局a

with 和 eval会使性能变差,使代码运行变慢,不要使用它们。

chapter Three 函数作用域和块级作用域

1
2
3
4
5
6
7
var a = 3;
(function foo() {
var a = 2;
console.log(a);//2
})();
foo();//ReferenceError not defined
console.log(a);//3

foo也不能在全局作用域中被访问
注意foo里面的a只属于函数foo作用域,函数外面的a属于全局作用域
var a 编译器向当前作用域询问是否包含该变量,如果是则忽略,否则会在当前作用域创建新的变量,命名为a

无块级作用域

1
2
3
4
5
6
var f = 2;
if(f){
var bar = f*2;
}
console.log(bar)//4
//无论f为真为假,bar都会是被声明的 var bar;

let
const也是块级元素,在外部无法访问

1
2
3
4
5
6
7
var foo = true;
if(foo){
var a = 2;
const b = 3;
}
console.log(a)//2
console.log(b)// ReferenceError not defined

chapter Four 提升

包括变量和函数在内的所有声明(函数声明会被提升,函数表达式不会)都会在任何代码被执行前首先被处理。
var a = 2;将被分为 var a,和a = 2,var a 会被提升,在编译阶段进行,第二个赋值声明留在原地等待执行阶段。
各变量在各自的作用域内进行提升。
函数比变量优先提升
重复的函数声明会被覆盖

在一个普通块内部的函数声明通常会被提升到作用域的顶部

1
2
3
4
5
6
7
8
9
10
11
12
foo();//TypeError foo is not a function
var a = true;
if(a){
function foo(){
console.log("a")
}
}
else{
function foo() {
console.log("b")
}
}

chapter Five 作用域闭包

当函数可以记住并访问所在的词法作用域时,就产生的闭包,即使函数是在当前词法作用域之外执行

1
2
3
4
5
6
7
8
9
10
function foo() {
var a = 2;
function bar() {
console.log(a)
}
return bar;
}
var baz = foo();
baz();//2

bar拥有foo内部作用域的闭包,使得foo作用域调用之后不会被回收而一直存活,以共bar之后任何时间使用。
bar依然持有对该作用域的引用,这个引用就叫做闭包。
无论通过何种方式将内部函数传递到所在的词法作用域以外,都会蚩尤对原始定义作用域的引用,无论在何处执行这个函数都会使用闭包。