本文翻译自 https://blog.bitsrc.io/hoisting-in-modern-javascript-let-const-and-var-b290405adfda,作者 Sukhjinder Arora,内容有部分删改,标题有改动。
许多 JavaScript 程序员将提升解释为 JavaScript 将声明(变量和函数)移至其当前作用域(函数或全局)顶部的行为。好像它们实际上已经移到了代码的顶部,事实并非如此。例如:
console.log(a);
var a = 'Hello World!';
他们会说,上面的代码将在提升后转换为以下代码:
var a;
console.log(a);
a = 'Hello World!';
尽管看起来是这样,因为代码也工作正常了,但是 JavaScript 引擎事实上并不是这么做的,你的代码还是在这里。
那么,提升是什么呢?
在编译阶段,即在代码执行前的几微秒内,将对其进行扫描以查找函数和变量声明。所有这些函数和变量声明都添加到内存中称为词法环境的 JavaScript 数据结构内部。这样,即使在源代码中实际声明它们之前也可以使用它们。
词法环境是什么?
词法环境是用来保存标识符和变量映射关系的地方。标识符是变量或者函数的名字,变量是对实际对象(包括函数对象和数组对象)或者原始值的引用。
简而言之,词法环境是存储变量和对象引用的地方。
词法环境的结构如下:
LexicalEnvironment = {
Identifier: <value>,
Identifier: <function object>
}
如果想要了解更多词法环境相关的内容,可以查看我翻译的这篇文章 面试必备 | 一文读懂 JavaScript 中的执行上下文。
现在我们知道了提升的内部原理是什么,让我们看看函数和变量(let
、const
、var
)声明的提升是如何发生的。
函数声明提升
helloWorld(); // prints 'Hello World!' to the console
function helloWorld(){
console.log('Hello World!');
}
我们已经知道函数声明是在编译阶段添加到内存的,因此我们可以在实际函数声明之前在代码中对其进行访问。
因此,以上代码的词法环境如下所示:
lexicalEnvironment = {
helloWorld: <func>
}