JavaScript中的变量提升

概述

对于初学者来说,经常会对变量的偶尔出现undefined的值出现的很多莫名其妙的结果难以理解,这种情况大多数时候都是由于JavaScript变量提升(Hoisting)而引起的。变量提升是JavaScript把声明提升到顶端的默认行为,理解JavaScript中的变量提升是学习JavaScript基础的基础。

变量提升

先来看两个示例。

1
2
3
4
// 示例一
x = 5; // 将5赋值给x
console.log(x); // 5
var x; // 声明x
1
2
3
4
// 示例二
var x; // 声明x
x = 5; // 将5赋值给x
console.log(x); // 5

上面两个例子的结果完全一样,实际上变量的声明会被提升到顶部,在示例一预编译之后的结果,就正好是实例二。再来看两个例子。

1
2
3
4
// 示例三
var x = 3;
console.log(x + y); // NaN
var y = 5;
1
2
3
4
// 示例四
var x = 3;
var y = 5;
console.log(x + y); // 8

上面的结果是不一样的。注意变量提升只会提升声明,并不会提升变量的初始化。示例三的代码等同于示例五。

1
2
3
4
5
6
// 示例五
var x; // undefined
var y; // undefined
x = 3
console.log(x + y); // 3 + undefined === NaN
y = 5;

函数提升

当使用函数声明定义函数的时候,函数也会被提升到顶端。来看如下示例。

1
2
3
4
5
// 示例六
console.log(foo()); // 5
function foo() {
return 5;
}

输出结果为5,上面的代码等同于示例七。

1
2
3
4
5
// 示例七
function foo() {
return 5;
}
console.log(foo()); // 5

和变量提升一样,使用函数声明定义的函数将会被提升到顶端。

特殊情况

还有两个地方需要特别注意的。ES6的let和const都是不存在变量提升的,只有var定义的变量才会被提升。如示例八中x在声明之前就被使用了,因此抛出错误。

1
2
3
4
// 示例八
x = 5; // 将5赋值给x
console.log(x); // Uncaught ReferenceError: x is not defined
let x; // 声明x
1
2
3
// 示例九
console.log(x); // Uncaught ReferenceError: x is not defined
const x = 5;

此外要注意函数声明(Function Declaration)和函数表达式(Function Expression)的区别。函数表达式中,由于函数是右值,因此其不会再预编译的时候被处理。需要特别注意这一点。

1
2
3
4
5
// 示例十
console.log(foo()); // Uncaught TypeError: foo is not a function
var foo = function() {
return 5;
}

参考

  1. JavaScript Hoisting - W3Schools
  2. Function Declarations vs. Function Expressions - JavaScriptWebLog