一、什么是变量提升
先思考下面代码
console.log(a);
var a = 1;
test();
function test(){
console.log('test is running')
}
结果是
console.log(a); // undefined
var a = 1;
test(); // test is running
function test(){
console.log('test is running')
}
b=2;
变量a
和函数test
的定义在使用之后,为什么没有报错呢?原因就是我们常说的变量提升
。
我们知道ES6之前没有块级作用域,只有全局作用域
和函数作用域
。JS在执行脚本之前会先解析代码
,在解析的时候会创建一个全局执行上下文
,并将其中的变量、函数
都先拿出来,并给它们提前在内存中开辟好空间,变量暂时赋值为undefined
,函数则会声明好
,整个存储在内存中,这一步做完了再正式执行程序
。函数在执行的时候同理,也会先解析代码,创建一个函数执行上下文
,将其中的变量、函数
提前准备好。
所以,当执行console.log(a)
的时候,JS解析器已经提前把a定义好并赋值为undefined。可以在函数定义前就调用。
二、变量提升的几点注意事项
1.不带var
修饰符的变量不会提升
console.log(a); // Uncaught ReferenceError: a is not defined
a = 1;
JS在解析变量时会查找var关键字
,如果变量没有通过var来定义,则不能提前定义。
2.函数名和变量名相同时,函数会覆盖变量
// 先定义变量再定义函数的时候
console.log(typeof a); // function
var a = 1;
function a(){}
// 先定义函数再定义变量的时候
console.log(typeof b); // function
function b(){}
var b = 2;
不好意思,function有主角光环,不管你变量怎么调整出场顺序,最后的赢家都是function
。
3.let 和 const不会有变量提升这种现象
console.log(a); // Uncaught ReferenceError: a is not defined
console.log(b);
let a = 1;
const b = 2;
按照一般的逻辑,变量应该在声明语句之后才可以使用,为了纠正变量提升这种现象,let和const改变了语法行为
,它所声明的变量一定要在声明后使用
,否则会报错。