变量提升-你不知道的JS

先有鸡还是先有蛋(现有声明再有赋值)

console.log( a );  // undefined
var a = 2;
  1. 引擎会在解释JavaScript 代码之前首先对其进行编译。
  2. 编译阶段中的一部分工作就是找到所有的声明,并用合适的作用域将它们关联起来。
  3. 正确的思考思路是,包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理。

当你看到var a = 2; 时,可能会认为这是一个声明。但JavaScript 实际上会将其看成两个
声明:var a; a = 2;
第一个定义声明是在编译阶段进行的。
第二个赋值声明会被留在原地等待执行阶段。

上面的代码片段会以如下形式进行处理

// 编译阶段
var a;
// 执行阶段
console.log(a);
a = 2;

这个过程就好像变量和函数声明从它们在代码中出现的位置被“移动”
到了最上面。这个过程就叫作提升

对于函数,函数声明被提升的救过就是,可以在声明前执行。

foo();
function foo() {
    console.log( a ); // undefined
    var a = 2;
}

每个作用域都会进行提升操作

对于函数表达式,不会存在提升。

foo(); // 不是ReferenceError, 而是TypeError!
bar(); // ReferenceError
wahtthefuck() // ReferenceError
var foo = function bar() {
    // ...
};

变量的提升会导致报ReferenceError,但是这里是TypeError。
foo() 由于对undefined 值进行函数调用而导致非法操作,因此抛出TypeError 异常。
至于bar(),外部作用域完全没有声明这个变量,所以报ReferenceError