概念
所有变量的声明语句都会被提升到代码头部,这就是变量提升。
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 bconsole.log(a) // undefinedvar a = 'Hello world'function b() {console.log('call b')}
在生成执行上下文时,会有两个阶段。第一个阶段是创建的阶段(具体步骤是创建 VO),JS 解释器会找出需要提升的变量和函数,并且给他们提前在内存中开辟好空间,函数的话会将整个函数存入内存中,变量只声明并且赋值为 undefined💛,所以在第二个阶段,也就是代码执行阶段,我们可以直接提前使用。
在提升的过程中,相同的函数会覆盖上一个函数,并且函数优先于变量提升
b() // call b secondfunction b() {console.log('call b fist')}function b() {console.log('call b second')}var b = 'Hello world'
var 会产生很多错误,所以在 ES6中引入了 let。let 不能在声明前使用,但是这并不是常说的 let 不会提升,let 提升了声明但没有赋值,因为临时死区导致了并不能在声明前使用。
