很多 Javascript 教程或者书籍中都会介绍 Javascript 的变量提升,但是你了解其中的原因吗?

现象

首先来看两个经典的案例 (案例均处于严格模式

案例一:

1
2
3
a = 1;
console.log(a);
var a;

这个很简单,变量提升最直接的体现,输出的结果是 1,实际的执行顺序如下:

1
2
3
var a;
a = 1;
console.log(a);

案例二:

1
2
console.log(a);
var a = 1;

这段代码执行会报错,不过错误是 a 是 undefined,而不是 ReferenceError,因为这段代码的实际执行顺序如下:

1
2
3
var a;
console.log(a);
a = 1;

解析

原理

要弄清楚 Javascript 变量提升,还得回到 Javascript 的编译阶段。

Part of the compilation phase was to find and associate all declarations with their appropriate scopes.

编译阶段的其中一个工作就是找到所有的声明,并用合适的作用域将它们关联起来,所有的变量声明以及函数声明都会在代码执行之前首先被处理。所以,分析 Javascript 代码的时候需要先关注声明。
这样就导致了 var a = 1; 被分解成了 var a; a = 1;,所以案例二的结果就很明显了。

函数优先

值得注意的是,变量提升时,函数声明优先,函数声明会被首先提升,其次才是变量,具体效果如下

1
2
3
4
5
6
7
8
foo();
var foo;
function foo() {
console.log(1);
};
foo = function() {
console.log(2);
};

执行的结果是 1,实际执行流程如下

1
2
3
4
5
6
7
8
function foo() {
console.log(1);
};
//var foo; //重复声明,被忽略
foo();
foo = function() {
console.log(2);
};

参考: