看下面的简单例子:
console.log(a); var a =2;JavaScript会将上面的声明看成两个声明:var a;和a=2;。第一个定义声明在编译阶段进行,第二个赋值声明会被留在原地等待执行阶段。 第一个代码片段会以如下形式进行处理:
var a; console.log(a); a = 2;这个过程就好像变量声明(函数声明也一样)从他们在代码中出现的位置被“移动”到了最上面,这个过程就叫作提升。
函数声明和变量声明都会被提升,但是有一个值得注意的细节:函数首先会被提升,然后才是变量。 考虑下面的代码:
foo(); var foo; function foo() { console.log(1); } foo=function() { console.log(2); };结果会输出1,而不是2。这个代码片段会被引擎理解为如下形式:
function foo() { console.log(1); } foo();//1 foo=function() { console.log(2); }尽管var foo 出现在function foo()的声明之前,但它是重复的声明,因此被忽略,因为函数的声明会被提升到普通变量之前。 虽然重复的var声明会被忽略掉,但是出现在后面的函数声明能够覆盖之前的声明:
foo();//3 function foo() { console.log(1); } var foo=function() { console.log(2); } function foo() { console.log(3); }以上这些内容虽然听起来没有太大用处,但是它说明了在同一个作用域中进行重复定义是非常糟糕的,而且经常会导致各种奇怪的问题。 一个普通快内部的函数声明通常会被提升到所在作用域的顶部,这个过程并不会像下面的代码暗示的那样可以被条件判断所控制:
foo(); var a=true; if(a) { function foo() { console.log('a'); } } else { function foo() { console.log('b') } }上述代码会被理解为如下形式:
function foo() {console.log('b')}; var a; foo(); a=true; if(a) {} else{}所以这个行为并不可靠,应该尽可能避免在块内部声明函数。