变量提升(Hoisting)
变量提升(Hoisting)被认为是, Javascript中执行上下文 (特别是创建和执行阶段)工作方式的一种认识。从概念的字面意义上说,“变量提升”意味着变量和函数的声明会在物理层面移动到代码的最前面,但这么说并不准确。实际上变量和函数声明在代码里的位置是不会动的,而是在编译阶段被放入内存中。
变量提升与函数提升
提升顺序: 先执行变量提升,再执行函数提升,JavaScript中的函数是一等公民,函数声明的优先级最高,会被提升至当前作用域最顶端。
JavaScript 仅提升声明,而不提升初始化。如果你先使用的变量,再声明并初始化它,变量的值将是 undefined。
//-----------------var 声明的变量提升---------------------------
console.log(a);//undefined
var a=123;//声明并初始化 a 为123
//------------------函数提升------------------------------
fn2() // 2,function 声明的函数变量会提升,「初始化」并「赋值」为 function(){ console.log(2) },也就是说 function 声明会在代码执行之前就「创建、初始化并赋值」
function fn2(){
console.log(2)
}
function foo(){
console.log(a); //undefined
var a=2; //var声明的变量存在变量提升,声明被提升,打印为undefined
}
foo();
//----------------函数表达式------------------------
console.log(fn3)//'undefined'
//fn3()//Uncaught TypeError: fn3 is not a function
var fn3 = function () {
console.log('fn3()')
}
fn3()//'fn3()'
//--------------let声明的变量提升问题------------------------
console.log(x) // Uncaught ReferenceError: Cannot access 'x' before initialization
let x = 'global'
由以上例子可以总结:
- 变量声明提升:由 var 声明的变量,在声明语句之前可以访问到,返回值为 undefined
- 函数声明提升:通过 function 声明的函数,可以在声明函数之前使用该函数。(正确的方式:先声明函数,再调用函数 (最佳实践))
- 函数表达式声明的变量会被当做变量提升,声明语句之后可以调用该函数
注: JavaScript 严格模式(strict mode)不允许使用未声明的变量。
在开发者工具中进行调试,设置断点,控制台打印 window,可以看出在运行到代码之前,window中已经有了提升的变量属性等,如图:

然而 let 声明的变量不能提升,文档中的解释为:
The variables are created when their containing Lexical Environment is instantiated but may not be accessed inany way until the variable’s LexicalBinding is evaluated.
当程序的控制流程在新的作用域(module function 或 block 作用域)进行实例化时,在此作用域中用 let / const 声明的变量会先在作用域中被创建出来,但因此时还未进行词法绑定,所以是不能被访问的,如果访问就会抛出错误。因此,在这运行流程进入作用域创建变量,到变量可以被访问之间的这一段时间,就称之为暂时死区。
因此:所谓暂时性死区,就是不能在变量初始化之前,使用变量。在代码块内,使用 let 命令声明变量之前,该变量都是不可用的。
变量提升与函数提升例题:
例题 1
function a() {
}
var a
console.log(typeof a)// 'function'
先执行变量提升,再执行函数提升,JavaScript中的函数是一等公民,函数声明的优先级最高,会被提升至当前作用域最顶端。
因此先声明变量 a ,然后 a 变量被函数 a 赋值,打印输出为 function
例题 2
if(!(b in window)){
var b = 1
console.log(b)//没有执行
}
console.log(b)//undefined
上面例子中,在 JavaScript 中 if 语句不创建新的作用域,默认是在全局作用域中,因此预编译时,var b 变量声明提升了,因此 变量 b 在全局对象 window 中,if 语句不满足条件不再执行,所以 打印 b 为 undefined
提升后代码相当于:
var b
if(!(b in window)){
b = 1
console.log(b)//没有执行
}
console.log(b)//undefined
例题 3
var c = 1
function c(c) {
console.log(c)
}
c(2)//Uncaught TypeError: c is not a function
因为变量提升与函数提升,因此提升后的代码相当于:
var c
function c(c) {
console.log(c)
}
c = 1
c(2)//Uncaught TypeError: c is not a function
所以运行代码后 变量 c 为 number 型数字 1,调用 c(2) 会报错。
参考文章:

本文深入探讨JavaScript中的变量提升(Hoisting)现象,包括var、let声明的提升特性,函数声明与表达式的提升区别,以及在不同作用域下变量提升的行为。通过多个示例代码,详细解释变量提升对代码执行的影响,帮助读者理解并避免常见陷阱。
9799

被折叠的 条评论
为什么被折叠?



