概念
所有变量的声明语句都会被提升到代码头部,这就是变量提升。
eg1
console.log(a);
var a =1;
以上语句并不会报错,只是提示undefined
。实际在js引擎中的运行过程是:
var a;
console.log(a);
a =1;
实际运行表示变量a已声明,但还未赋值。
但是变量提升只对var命令声明的变量有效,如果一个变量不是用var命令声明的,就不会发生变量提升。
console.log(aa);
aa =1;
以上代码将会报错:ReferenceError: aa is not defined
。
补充:js里的function
也可看做变量,也存在变量提升情况
a();
function a(){
console.log(1);
};
表面上,上面代码好像在声明之前就调用了函数a
。但是实际在js引擎中,由于“变量提升”,函数a
定义部分被提升到了代码头部,也就是在调用之前已经声明了。
但是!如果采用赋值语句定义函数,JavaScript就会报错:
a();
var a = function(){
console.log(1);
};
// TypeError: a is not a function
因为js引擎把变量声明提升,此时,a就是一个变量,而并不是一个function,以下是js引擎实际运行代码:
var a;
a();
a = function(){
console.log(1);
};
PS函数声明方式区别
// 函数表达式
var f = function() {
console.log(1);
}
// 直接声明
function f (){
console.log(2);
}
第一种方式,函数只能在声明之后调用。因为这种方式声明的函数,是在函数运行的阶段才赋值给变量 f 的;
第二种方式,函数可以在声明函数的作用域内任一地方调用。因为这种方式,是在函数解析阶段赋值给标识符 f .
值得注意的是,当同时使用这两种方式声明同一个函数名,最终执行的是函数表达式声明的函数。
// 函数表达式
var f = function() {
console.log(1);
}
// 直接声明
function f (){
console.log(2);
}
f();
// 1
例子
b() // call b
console.log(a) // undefined
var a = 'Hello world'
function b() {
console.log('call b')
}
在生成执行上下文时,会有两个阶段。第一个阶段是创建的阶段(具体步骤是创建 VO),JS 解释器会找出需要提升的变量和函数,并且给他们提前在内存中开辟好空间,函数的话会将整个函数存入内存中,变量只声明并且赋值为 undefined💛,所以在第二个阶段,也就是代码执行阶段,我们可以直接提前使用。
在提升的过程中,相同的函数会覆盖上一个函数,并且函数优先于变量提升
b() // call b second
function b() {
console.log('call b fist')
}
function b() {
console.log('call b second')
}
var b = 'Hello world'
var
会产生很多错误,所以在 ES6中引入了 let
。let
不能在声明前使用,但是这并不是常说的 let
不会提升,let
提升了声明但没有赋值,因为临时死区导致了并不能在声明前使用。