在javascript里存在一种叫变量声明提升的东西。这里来详细的说一说,到底什么样的声明会提升,提升了什么东西。
先来两个例子考考你:
a =2 ;
var a;
console.log(a);
你是不是觉得var a 的声明在a = 2的后面,认为变量被重新的赋值了,所以是undefined 。但是实际上真正的输出结果是2。这是为什么呢?不要急,再来看一个例子
console.log(a)
var a = 2;
如果你受到上面的例子影响你可能会误认为答案是2,也可能认为变量a没有声明直接使用会导致错误,但是实际上真正的答案是undefined。
现在,我们来看一下到底发生了什么事情吧。
相信你是知道变量声明提升的存在的。编译器会将变量和函数在内的所有声明提到所有代码未执行之前进行处理。var a = 2; 实际上会被编译器解析成两部分,首先是变量的声明,var a;然后是变量的赋值 a = 2;而声明部分将会在编译阶段进行处理,赋值则会留在原地等待代码执行到这里。
所以第一个例子中,最终会是这样的形式被处理。
var a;
a = 2;
console.log(a)
可能有些对变量声明提升有了解的同学知道,第一个例子里面的a = 2;本身就会出现一个变量的声明提升,但是下面有出现了一个变量的声明,在编译过程中,出现了两次var a的声明,实际上重复的声明是会被忽略掉的。
第二个例子就容易理解了,最终被解析成
var a ;
console.log(a)
a = 2;
说了变量声明提升,我们现在来说函数的声明提升。之前写代码的时候你可能已经发现了,函数写在我们js文件的任何位置都可以正常的执行,这就是函数声明提升的原因。
foo();
function foo(){
console.log(a);
var a = 2
}
这里的a最终会被输出undefined。函数的声明会被提升到最上面,所以我们的foo()是不会造成错误的。这里我们重点看一下,a的声明提升。在函数的内部,就是局部的作用域内也是会对变量的声明进行提升的,当然这里不会提升到全局作用中。
上面的例子最终会被解析成
function foo(){
var a;
console.log(a)
a=2;
}
foo();
这里要特别提一下的是,函数的声明会提升,但是函数表达式不会不会被提升的。只会提升函数表达式的变量标识符。
举个例子:
foo();
var foo = function() {
}
这里会被解析成
var foo;
foo();
foo = function() {}
现在,我们知道函数的声明和变量的声明都会被提升,但是函数会优先被提升,然后才是变量,加上前面我们说过的重复的声明会被覆盖掉,所以当函数和变量同名时,在编译阶段会优先提升函数的声明,然后忽略同名的变量声明。看下面的例子;
foo();
var foo;
function foo(){
console.log(1)
}
foo = function() {
console.log(2)
}
最终将被解析为
function foo () {
console.log(1)
}
foo();
foo = function() {
console.log(2)
}
但是,注意了这里有个但是,但是如果是同名的函数,函数声明虽然会被忽略,但是后面的函数声明还是会覆盖掉前面的,所以,写代码的时候,注意这个问题,避免出现同名函数以及变量。