题目
有些朋侪可能会以为javascript的代码是从上到下,一行一行的诠释实行的。假如根据如许的思绪,在有些状况下浏览代码会获得毛病的结果,斟酌以下代码:
a = 2;
var a;
console.log(a);
console.log(a)
应当输出什么呢?有些开发者以为会输出undefined
,由于var a
在’a = 2’以后,变量a
被反复定义了,然则没有被赋值,所以是’undefined’。然则结果输出是2
。以下图所示:
我们再来斟酌另一段代码,以下所示:
console.log(a);
var a = 2;
这段代码会输出什么样的结果呢?有些人可能会以为输出ReferenceError
。由于变量a
在没有声明的状况下就被使用了。实在结果呢,以下图所示:输出的是undefined
为何会如许呢?这就牵出了本文的主题:JavaScript声明提拔
JavaScript代码的运转划定规矩
在JavaScript代码运转之前实际上是有一个编译阶段的。编译以后才是从上到下,一行一行诠释实行。变量提拔
就发作在编译阶段,它把变量和函数的声明提拔至作用域的顶端。(编译阶段的事情之一就是将变量与其作用域举行关联)。
所以关于代码var a =2;
来讲,编译器看到的是两行代码var a; a = 2;
第一个语句是声明语句,在编译阶段处置惩罚。第二个语句是赋值语句,在运转阶段处置惩罚。
那末我们再回过头来看看题目中涌现的代码:
a = 2;
var a;
console.log(a);
应当如许来处置惩罚:
var a; //编译阶段
a = 2; //运转阶段
console.log(a); //运转阶段
所以这段代码的终究输出的结果是2
。
第二段代码:
console.log(a);
var a = 2;
应当如许来处置惩罚:
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。