理解JavaScript的变量提升(译)

原文链接:https://medium.com/better-programming/hoisting-in-javascript-6af97650dbb2

如果你是萌新,”变量提升”在JavaScript是一个难以理解的知识点。它几乎困惑了所有人。不要担心,我将会帮助你理解在JavaScript中”变量提升”工作机制。

什么是变量提升?

“变量提升”是移动所有定义到当前作用域顶部的JavaScript默认行为。

JavaScript没有提升以下项目:

  • 1.用表达式定义的函数
  • 2.用let或者const定义的变量和常量
  • 3.箭头函数

在JavaScript中,一个变量可以被使用在它被定义之前。

1
2
3
x = 5;
console.log(x * 2); // Prints 10 in the console
var x;

好的…,但这是什么意思?我没有理解你要说的。

让我来通过几个新例子帮助你理解

1
2
3
4
5
6
7
8
9
10
11
12
// Example 1

function foo(){
function bar() {
return 7;
}
return bar();
function bar() {
return 11;
}
}
console.log(foo()); // Prints 11

当一个函数定义被提升的时候整个函数体将被提升。因此解释完成第一个示例代码之后,它更像这样运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
unction foo(){
//define bar once
function bar() {
return 7;
}
//redefine it
function bar() {
return 11;
}
//return its invocation
return bar();
}
console.log(foo());

But… isn’t the code after a return statement unreachable?(这句有点看不懂)

在JavaScript执行中,有上下文( ECMA 5 分为词法环境,变量环境,和绑定this指针)和进程(一组按顺序调用的语句)。当进入执行作用域时,定义贡献变量环境。它与语句不同的是它不受进程规则的限制。

让我们再看一个例子,这次是一个函数表达式。

1
2
3
4
5
6
7
8
9
10
11
12
// Example 2

function foo(){
var bar = function() {
return 7;
};
return bar();
var bar = function() {
return 11;
};
}
console.log(foo()); // Prints 7

注意到当变量被创建时初始化是undefined。具有”初始值”的变量实在执行时分配表达式的值,而不是变量被创建的时候。

1
2
3
var myFunction = function () {
// some executable code
}

在上面的代码片段中,左边的var myFunction是一个变量声明定义。

变量声明得到提升,但是他的分配表达式没有提升。所以,当myFunction被提升的时候,解释器初始化设置var myFunction = undefined。函数定义没有提升。

记住上面所有的知识点,然后让我们来看下例2如何工作的。

它运行就像这样:

1
2
3
4
5
6
7
8
9
10
function foo(){
var bar = undefined; // declaration for first function expression
var bar = undefined; // declaration for second function expression
//first function expression is executed
bar = function() {
return 7;
};
return bar(); // function created by first function expression is invoked
}
console.log(foo()); // Prints 7

在调用第一个函数表达式后,第二个函数表达式无法访问。

在顶部声明你的变量以免混乱

变量提升非常有趣但它可能会导致bug,因为十分容易被忽略。

你可以使用严格模式,在顶部使用use strict指令。JavaScript严格模式下不允许使用还没有定义的变量。