在讲JS变量提升的时候,我们先要了解JS代码运行的逻辑顺序,和一些作用域的概念。这样我们就能很简单地理解什么是变量提升了
JS代码的执行顺序:先编译,后执行
编译阶段
- 词法分析,语法分析,生成AST(Abstract Syntax Tree ),将AST转变成可执行代码。也就是说编译阶段的时候,编译阶段的产出就是可执行代码。而这个工作就是编译器的工作
- 在生成可执行代码的过程中,编译器还会去做一件事,这就是声明var变量,或者是function
var a;
对于这样一段代码,编译器首先会在当前作用域查找是否已经声明了a变量,如果已经有了a变量,就会忽略该声明;否则会要求作用域在当前作用域的集合中声明一个新的变量
这段描述的结尾似乎很奇怪。似乎声明变量是需要作用域相关代码参与的
- 编译结束,生成了可执行的代码。在当前作用域,已经有了a的变量声明,但是值为undefined。
执行阶段
这个阶段的执行的任务就是JS引擎的事了,这个我们放在作用域那块再讲
什么是变量提升
了解了编译阶段的动作之后,了解这个就很简单了
变量提升, 就是在代码编译结束之后,代码执行之前,代码中的变量声明就已经存在于当前的作用域中了
为什么会有变量提升
据说是当是设计语言的时候,时间比较赶,就这样处理了。变量提升会导致一系列的问题,并且编程也不够灵活,所以JavaScript后面又设计除了块作用域。这个我们之后再讲。
哪些东西可以变量提升
- var声明的变量
- 形如
function foo() {}这样的一个声明 这样会导致下面的情况
foo(); //'foo'
console.log(a); // undefined
bar(); //TypeError
var a = 1;
foo(){
console.log('foo');
}
var bar = function(){
console.log('bar')
}
第1行和第2行的执行结果,我们很好理解。
第3行的结果这里要特别说明一下
- 当代码编译完成之后,当前作用域确实已经存在了bar这个变量,但是bar这个变量的值为undefined
- bar的赋值操作需要等到代码执行才会去做
- 也就是说,没有执行赋值操作之前,bar就一直是undefined。而对undefined的变量做函数调用的操作,就会报
TypeError的错误
总结
- 代码的执行顺序:先编译后执行
- 什么是变量提升:代码真正执行之前,声明的变量就已经存在于作用域中
- 哪些东西可以变量提升:形如
var和function foo() {}这样的声明 - 下篇更精彩 😁