变量声明提升
在JS中,我们在使用变量前一般都会先声明它,一般我们常见的是使用 var
关键字对变量进行声明。当然,直接使用 var
关键字的声明我们可以称为显示声明,而有些情况,没有使用 var
关键字,也依旧是对变量进行了声明,只不过我们没有看到,这是JS内部进行的隐式声明。下面我们来解释一下这两种声明方式:
- 显示声明
var a = 1;
上面代码中直接使用 var
关键字对变量 a
进行了声明,并且在对 a
进行操作前,变量 a
的声明会提升到其当前所处的作用域的顶部,所以,上面的执行过程相当于:
var a;
a = 1;
相当于先对 a
进行声明,且是提到其作用域的顶部的,这就叫做变量声明提升,但是对变量的赋值操作是不会被提升的。
- 隐式声明
在函数内部,如果没有使用 var
关键字声明的变量,如:
function test(){
a = 1;
}
此时,变量 a
被隐式声明为全局变量,相当于在函数体的顶部,对变量 a
进行了声明:
function test(){
var a;
a = 1;
}
还有一种情况是,函数中的参数列表中的形参,我们一般都是直接使用的,其实它也是进行了隐式的变量声明,而其作用域就是其所在的函数作用域:
function add(a,b){
return a+b;
}
如上述代码,变量 a
和 b
是函数 add
的两个形参,此时,在函数内部相当于对这两个变量进行了声明,并且提升在函数作用域的顶部,相当于:
function add(a,b){
var a,b;
return a+b;
}
但是,这个是在其内部自动就完成的声明,所以称为隐式声明,并且会提升到其所在作用域顶部的。
函数声明提升
函数由关键字 function
进行声明,函数声明没有 显示 和 隐式 之分。一般函数执行语句都是写在函数下方的,但是如果函数执行语句在写在了函数的上方,如下:
test();//1
function test(){
console.log(1);
}
如上述代码,这样写的话就会出现函数声明提升,即在执行 test();
语句之前,会先把整个函数声明提升到作用域的最顶部,然后再执行 test();
语句,相当于:
function test(){
console.log();
}
test();//1
这个就叫做函数声明提升。
当然,对于函数,我们有两种表示方式,一直是上面说的函数声明,另外一种则是函数表达式,但是函数表达式是将一个匿名函数赋值给一个对象变量,并且这个对象变量是变量声明的,我们把这种情况归为变量声明的范畴。
变量声明提升与函数声明提升的顺序
变量声明和函数声明都会提升,那么总有个先后顺序吧,那谁先,谁后呢?眼力尖的人可能已经注意到我前面形容变量声明提前用的词是顶部,而函数声明提前用的是最顶部。
所以,答案是 函数声明提升在前,变量声明紧随其后。
网上有的人说是变量声明在前,但是也只是说说,说的话还是要有证据证明才行!
证明:
- 《JavaScript权威指南(第6版)(中文版)》中第94页指出,变量声明语句会被提升至脚本的顶部。
- 《JavaScript权威指南(第6版)(中文版)》中第95页指出,函数声明语句通常出现在JavaScript代码的最顶部。
- 《JavaScript权威指南(第6版)(中文版)》中第96页指出,脚本中所有函数和函数中所有的嵌套的函数都会在当前上下文中其他代码之前声明。
- 《你不知道的JavaScript(上卷)》中第40页中指出,函数会首先被提升,然后才是变量。
关于函数名和变量名同名的问题总结
先看一段代码:
foo();//1
function foo(){
console.log(1);
}
var foo = function(){
console.log(2);
}
此处,为什么会输出 1
而不是 2
呢?上述的代码片段会被引擎理解为如下形式:
function foo(){
console.log(1);
}
var foo;
foo();
foo = function(){
console.log(2);
}
注意,var foo
是出现在 founction foo(){}
之后再进行声明的,并且这里的变量 foo
声明重复了。尽管声明重复,但是对变量 foo
没有影响,因为提升的只是变量,其赋的值还留在原来的位置。
对于重复声明的变量,《JavaScript权威指南(第5版)中文版(上)》第59页给出了这样的解释:使用 var 语句多次声明同一个变量不仅是合法的,而且也不会造成任何错误。
本篇文章都是有理有据的分析,在此记录!
参考文献:
《JavaScript权威指南(第5版)中文版(上)》
《JavaScript权威指南(第6版)(中文版)》
《你不知道的JavaScript(上卷)》