很多人在初学JS接触到变量,函数的时候,总会碰到一个很棘手的问题----变量/函数提升.
变量提升,顾名思义,就是把定义在后面的变量或者函数,提升到前面来使用.
然而变量提升之所以存在疑点,是因为它涉及到了作用域(scoping)的问题.所以在讲变量/函数提升之前,我们先来研究一下作用域的问题.
JavaScript的scoping如此复杂的原因是它看上去非常像C系语言的成员。我们首先来看一段C程序
#include
int main() {
int x = 1;
printf("%d, ", x); // 1
if (1) {
int x = 2;
printf("%d, ", x); // 2
}
printf("%d\n", x); // 1
}
var x = 1;
console.log(x); // 1
if (true) {
var x = 2;
console.log(x); //2
}
console.log(x);// 2
这段代码的返回结果是1,2,2.
这是因为JavaScript是函数级作用域(function-level scope)。这和C系语言是完全不同的。块,就像if语句,for循环语句,都不会创建一个新的作用域,
只有函数才会创建新的作用域,
而且JS中重复定义变量并不会产生报错,只是新定义的变量值覆盖了之前定义所赋的值。
那么接下来,我们就可以深入的理解一下到底变量/函数提升是怎么一回事了
1.变量提升
变量提升,简单来说,就是把变量提升到一块作用域当中(或者说一个函数)顶端的位置,需要注意的是,变量提升,只是提升变量的声明,并不会将变量的赋值一同提升上来.
比如下面一段代码
(function(){
var a='One';
var b='Two';
var c='Three';
})()
我们定义了3个变量,而事实上,这种写法相当于接下来这段代码
(function(){
var a,b,c;
a='One';
b='Two';
c='Three';
})()
这就是变量提升的本意.
那么我们来看接下来一段代码,分析看看,这段代码的结果到底应该是什么呢?
var v='abc';
alert(v);//①abc
(function(){
alert(v);//②undefined
var v='123';
alert(v);//③123
})()
alert(v);//④abc
每一个结果都标注好了,有的朋友会问了,怎么会有一个undefined?
这段代码用一个函数划定了两个作用域,一个是全局,另外一个是函数内,①和④都被划定在函数外,并不受函数内的定义变量影响,故返回结果都是'abc',而函数内的返回结果,相信你看了下面这个代码段就清楚是怎么一回事了.
(function(){
var v;
alert(v);//②undefined
v='123';
alert(v);//③123
})()
怎么样?不需要再过多的解释,我相信大家看到这里一定都明白了!
2.函数提升
在我们写js 代码的时候,我们有两种写法,一种是函数表达式,另外一种是函数声明方式。
函数表达式 var fn=function fn(){}
函数声明方式 function fn(){code}
我们需要重点注意的是,只有函数声明形式才能被提升。
变量赋值并没有被提升,只是声明被提升了。但是,函数的声明有点不一样,函数体也会一同被提升
函数提升是把整个函数都提到前面去。
接下来我们看两段代码
(function test3() {
fn();
function fn() {
console.log("我来自fn test3");
}
}) ()
function test4() {
fn();// fn is not a function
var fn = function fn() {
console.log("我来自 fn test4");
}
fn();
}
test4();
这就是变量/函数提升的全部内容了.如果你有问题,或者还有更好的见解,欢迎评论交流!