JavaScript中常听见的名词。变量提升,感觉好高大上的样子,其实也没多神秘。有可能是我不求甚解。中心概念就是:在某一作用域中,声明变量的语句会默认解析为在该作用域的最开始就已经声明了。不理解作用域的同学先理解一下作用域的定义,简单来说就是变量的有效区,出了这个区域,就找不到这个变量了。我在下一篇博文应该会详细介绍一下作用域闭包的概念。
说回主题,直接上栗子吧:
var a = 5;
function foo(){
a =2
console.log(a);
var a;
}
foo()//2
够简单的代码了吧。我们可以看到,var a;语句并没有刷新a的值,因为,解析编译的时候,’var a;’被提前了.所以我们看的a是内部变量a而不是外面已赋值的5。
再来一个栗子:
var a = 5;
function foo(){
console.log(a);
var a =0;
}
foo()//undefind
在这里我们发现了什么问题呢,由于变量提升的原因a已经声明,所以没有输出我们再外部声明的5,但是’a=0;’并没有被提前执行。
所以变量提升这个概念,只适用于声明变量的语句,而变量赋值的语句并不能被提前(如果执行语句可以随意调换顺序,其破坏性可想而知)。我们再看看函数的提升,这个就非常常见了。比如举一个栗子:
foo();
function foo(){
console.log(1);
}
相信很多人都写过这样的代码吧。并不会因为函数没有提前写好就不能用吧。但是请注意,这里函数是直接通过声明来定义的。看看下面这段代码。
foo();//TypeError
var foo = function fooo(){
console.log(2);
}
这里的foo被提升了,所以这里并没有发生ReferenceError,但是这个时候foo并没有被赋值,所以发生了TypeError。这段代码经过提升后是这样的:
var foo;
foo();//TypeError
foo = function fooo(){
console.log(2);
}
我们习惯将‘var a = 3’看做一条声明。其实这里两条语句的简写,‘var a’和‘a = 3’,并且其实这两条语句是两个不同类型的语句,是由两个不同的组件完成的。前一句是在编译阶段执行,后一句是在运行阶段执行。所以,不管’var a’写在哪里,都会在代码本身被执行之前处理。这一过程很像是代码的一个移动过程,所以被大家称为“变量提升”。