提升

我们习惯将 var a = 2; 看作一个声明,而实际上 JavaScript 引擎并不这么认为。它将 var aa = 2 当作两个单独的声明,第一个是编译阶段的任务,而第二个是执行阶段的任务。

这意味着无论作用域中的声明出现在什么地方,都将在代码本身被执行前首先进行处理。可以将这个过程形象成所有声明(变量和函数)都会被「移动」到各自作用域的最顶端,这个过程被称为提升。

任何声明在某个作用域内的变量,都将附属域这个作用域,而每个作用域都会进行提升操作。

先有「声明」,后有「赋值」

**只有声明本身会被提升,而赋值或其他运行逻辑会留在原地。**如果提升改变了代码执行的顺序,会造成非常严重的破坏。

提升是指声明会被视为存在于其所出现的作用域的整个范围内。

使用let进行的声明不会在块作用域中进行提升,声明的代码在运行之前,声明并不存在。

1{
2  console.log(bar); // ReferenceError
3  let bar = 2;
4}

函数优先

函数声明和变量声明都会被提升。

避免重复声明:在存在多个「重复」声明的代码中,特别是当普通的 var 声明和函数声明混合在一起的时候,函数会首先被提升,然后才是变量。

1foo();
2// 同一标识符重复的声明,函数声明被提升到普通变量之前,因此被忽略了
3var foo = function () {
4  console.log(2);
5};
6
7function foo() {
8  console.log(1);
9}
10
11// output: 1
12
13// 后面的函数声明还是可以覆盖前面的
14function foo() {
15  console.log(3);
16}
17
18// output: 3