变量与函数提升

  1. var 变量总是提升到当前函数作用域的顶端
  2. let,const 为块级作用域,

变量声明提升

var与let作用域规则不一样

  1. var: 变量总是提升到当前函数作用域的顶端
  2. let: 当前块的作用域
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function varTest() {
var x = 1;
{
var x = 2; // 同样的变量!
console.log(x); // 2
}
console.log(x); // 2
}

function letTest() {
let x = 1;
{
let x = 2; // 不同的变量
console.log(x); // 2
}
console.log(x); // 1
}

let 可以用来创建类的私有属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var Thing;

{
let privateScope = new WeakMap();
let counter = 0;

Thing = function() {
this.someProperty = 'foo';

privateScope.set(this, {
hidden: ++counter,
});
};

Thing.prototype.showPublic = function() {
return this.someProperty;
};
}

let 不能重复声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if (x) {
let foo;
let foo; // SyntaxError thrown.
}

if(x) {
var foo;
var foo;
}

let x = 1;
switch(x) {
case 0:
let foo;
break;

case 1:
let foo; // SyntaxError for redeclaration.
break;
}

let, const 存在暂存死区

  1. var: 变量提升,会被移动到函数顶端,被初始化为undefined,存在函数堆栈内
  2. let: 不会变量提升,直至显示赋值才会被加入函数执行堆栈内,在块级作用域开始时,会被放到暂存死区, 无法被引用
1
2
3
4
5
6
// prints out 'undefined'
console.log(typeof undeclaredVariable);

// results in a 'ReferenceError'
console.log(typeof i);
let i = 10;

习题解释

1
2
3
4
5
6

// code01
let x = 1;
{
var x = 2; // SyntaxError for re-declaration
}
1
2
3
4
5
6
7
// code02
var x = 1;
{
let x = 2;
x++;
}
console.log(x); // 1
  1. code01: var 会被提升到函数的顶端, 因此处于同一块级作用域,所以抛异常SyntaxError
  2. code02: ++ 修改的是块级作用域内的 x 的值,所以 外面 x 的值不变

函数声明提升

普通提升

1
2
3
4
5
hoisted(); // "foo"

function hoisted() {
console.log("foo");
}
1
2
3
4
5
6
var hoisted; 

hoisted = function() {
console.log("foo");
}
hoisted();

相同点:

  1. var, function 都会被提升

不同点:

  1. var 提升在 function 之前
  2. var 为函数级提升,function 为块级提升

有条件提升

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// code01
foo(); // Uncaught TypeError: foo is not a function
{
function foo(){ return 1; }
}

// 在Chrome里:
// 'foo' 变量名被提升,但是 typeof foo 为 undefined
//
// 在Firefox里:
// 'foo' 变量名被提升. 但是 typeof foo 为 undefined
//
// 在Edge里:
// 'foo' 变量名未被提升. 而且 typeof foo 为 undefined
//
// 在Safari里:
// 'foo' 变量名被提升. 而且 typeof foo 为 function
1
2
// code02
foo(); //Uncaught ReferenceError: foo is not defined
  1. code01: 变量提升,函数未提升,执行undefind(),所以报错:TypeError
  2. code02: foo 没有被声明,没有找到foo,所以报错: ReferenceError