参考:《你不知道的JavaScript》上卷 第一部分 第四章

原理

引擎会在解释 JavaScript 代码之前首先对其进行编译。编译阶段中的一部分工作就是找到所有的声明,并用合适的作用域将它们关联起来。

正确的思路:包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理。

例子

例子1:

a = 2;
var a;
console.log(a);  // 2
console.log(a);  // undefined
var a = 2;
  • 只有声明本身会被提升,而赋值或其他运行逻辑会留在原地。如果提升改变了代码执行的顺序,会造成非常严重的破坏。

例子2:

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

foo 函数的声明(这个例子还包括实际函数的隐含值)被提升了,因此第一行中的调用可以正常执行。

  • 另外值得注意的是,每个作用域都会进行提升操作。

  • 声明会被会被提升,但是函数表达式却不会被提升。

看下面改造后的例子:

foo();
var foo = function () {
  console.log( a );
  var a = 2;
}
//  报错: Uncaught TypeError: foo is not a function

讲解(来自饥人谷)

在进入一个执行环境后,先把 var 和 function 声明的变量前置, 再去顺序执行代码。

是 var 声明在前还是 function 声明的在前? who care, 按先来后到,同名覆盖。当然如果一个变量已经有值,再 var 是无效的

var fn
function fn(){}

console.log(fn)  //function
function fn(){}
var fn   //已经声明过 fn, 再 var 无效,并不会重置为 undefined

console.log(fn)  //function

再来看几个例子

console.log( fn )
var fn = 1
function fn(){}
console.log( fn )
//  function
//  1
console.log(i)
for(var i=0; i< 3; i++){
  console.log(i)
}
//  undefined
//  0
//  1
//  2
var a = 1
function fn(){
  a = 2
  console.log(a)
  var a = 3
  console.log(a)
}
fn()
console.log(a)
//  2
//  3
//  1

(完)