有些朋友可能会以为javascript的代码是从上到下,一行一行的解释执行的。若是按照这样的思路,在有些状况下阅读代码会获得错误的结果,考虑如下代码:javascript
a = 2; var a; console.log(a);
console.log(a)
应该输出什么呢?有些开发者以为会输出undefined
,由于var a
在'a = 2'以后,变量a
被重复定义了,可是没有被赋值,因此是'undefined'。可是结果输出是2
。以下图所示:java
咱们再来考虑另外一段代码,以下所示:函数
console.log(a); var a = 2;
这段代码会输出什么样的结果呢?有些人可能会以为输出ReferenceError
。由于变量a
在没有声明的状况下就被使用了。真实结果呢,以下图所示:输出的是undefined
优化
为何会这样呢?这就牵出了本文的主题:JavaScript声明提高spa
在JavaScript代码运行以前实际上是有一个编译阶段的。编译以后才是从上到下,一行一行解释执行。变量提高
就发生在编译阶段,它把变量和函数的声明提高至做用域的顶端。(编译阶段的工做之一就是将变量与其做用域进行关联)。
因此对于代码var a =2;
来讲,编译器看到的是两行代码var a; a = 2;
第一个语句是声明语句,在编译阶段处理。第二个语句是赋值语句,在运行阶段处理。
那么咱们再回过头来看看问题中出现的代码:3d
a = 2; var a; console.log(a);
应该这样来处理:code
var a; //编译阶段 a = 2; //运行阶段 console.log(a); //运行阶段
因此这段代码的最终输出的结果是2
。 blog
第二段代码:图片
console.log(a); var a = 2;
应该这样来处理:ip
var a; //编译阶段 console.log(a); //运行阶段 a = 2; //运行阶段
因此这段代码的最终输出结果是undefined
。
变量提高
须要注意两点:
提高的部分只是变量声明,赋值语句和可执行的代码逻辑还保持在原地不动
提高只是将变量声明提高到变量所在的变量范围的顶端,并非提高到全局范围,说明以下:
foo(); function foo(){ console.log(a); //会输出undefined var a = "2"; } //变量提高以后的效果 function foo(){ var a; console.log(a); a = "2"; } foo();
函数声明会提高,可是函数表达式就不了
。看以下代码:
foo(); var foo = function bar(){ //这是一个函数表达式,再也不是函数声明。 console.log("bar"); }
处理方式以下:
var foo; foo(); //TypeError,由于尚未赋值 bar(); //bar不能够在全局范围内引用 foo = function bar(){ console.log("bar"); }
变量声明和函数声明都会获得变量提高,但函数声明会最早获得提高,而后是变量声明。
考虑以下代码:
foo(); //输出的结果为1 var foo; function foo(){ console.log(1); } foo = function(){ console.log(2); }
处理方式以下:
function foo(){ console.log(1); } foo(); foo = function(){ console.log(2); }
注意:var foo;
因为是重复声明变量,因此被编译优化去掉。
对于函数声明来讲,若是定义了相同的函数变量声明,后定义的声明会覆盖掉先前的声明,看以下代码:
foo(); //输出3 function foo(){ console.log(1); } var foo = function(){ console.log(2); } function foo(){ console.log(3); }
JavaScript中是没有块级做用域的概念(ps:ES6中有改进了),看以下代码:
foo(); //输出结果为2 var a = true; if(a){ function foo(){ console.log(1); } }else{ function foo(){ console.log(2); } }
这段代码输出结果为2,if语句没有块级做用域的功能,因此函数声明都被提高到全局做用域中,又由于定义了两个foo,后来的定义覆盖了前边的定义,因此输出结果为2。