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