声明提升
我们知道,JavaScript语句在编译阶段会将所有函数和变量的声明进行提升,例如:
console.log(a); // undefined var a=100;
输出是undefined,因为这个代码片段会被解析成:
var a; console.log(a); // undefined a=2;
变量a的声明会被提升到所在作用域(即全局作用域)的顶部,函数也不例外(注意,函数表达式是不会被提升的,只有函数声明才会被提升):
foo(); // 2 function foo(){ console.log(2); }
这个代码片段会被解析成:
function foo(){ console.log(2); } foo(); // 2
那函数和变量哪个会被优先提升呢?来看一个例子:
foo(); // 2 var foo; function foo(){ console.log(2); } foo=function(){ console.log(1); }
输出是2,实际上代码会被解析成:
function foo(){ console.log(2); } foo(); // 2 foo=function(){ console.log(1); }
虽然foo函数的声明在var foo;之后,但由于函数被优先提升了,所以var foo;也就因为重复声明而被忽略。
注意,出现在后面的函数声明可能会覆盖前面的:
foo(); // 3 functio foo(){ console.log(1); } var foo=function(){ console.log(2); }; function foo(){ console.log(3); }
foo();执行结果是3。实际上代码会被解析成:
functio foo(){ console.log(1); } function foo(){ console.log(3); } foo(); // 3 foo=function(){ console.log(2); };
声明会被提升到所在作用域的顶部,ES5不会像下面这样被条件语句所控制:
foo(); // 2 if(true){ function foo(){ console.log(1); } } else{ function foo(){ console.log(2); } }
输出是2而不是1,实际上代码会被解析成:
function foo(){ console.log(1); } function foo(){ console.log(2); } foo(); // 2 if(true){} else{}
第一个foo函数声明被第二个foo函数声明所覆盖,所以最终执行结果为2,因为尽管foo函数是在if-else语句块里被声明,但ES5没有块作用域(只有函数作用域),所以foo函数声明依然会被提升到全局作用域,就出现了刚才的情况。