本文深入解析 JavaScript 中的变量提升(Hoisting)机制。通过对比 var、let、const 以及函数声明式与表达式,阐明编译阶段内存分配原理。重点说明 var 的 undefined 提升、函数体连带提升及优先级规则,并指出 let/const 不存在提升的特性,帮助开发者避免引用错误与覆盖陷阱。
JavaScript 变量提升机制概述
简介
关于“变量提升”的常见误解是认为变量和函数的声明在物理层面被移动到了代码最前面,这种说法并不准确。
实际上,变量和函数在源代码中的位置保持不变,而是在代码编译阶段,它们的声明会被放入内存中。
变量与函数的声明方式
声明变量的方法
var、let、const
若不使用上述关键字直接赋值,变量会挂载到全局环境(如浏览器的 window 对象)中。
let a=9
const a=1
var a=6
c=5
声明函数的方法
在 JavaScript 中,声明函数主要有两种方式:函数声明式和函数表达式。
//函数声明
function say(){
console.log('hello')
}
//函数表达式
var say=function (){
console.log('hello')
}
变量提升的实际优势
提升的好处
JavaScript 在执行任何代码段之前,会将函数声明放入内存中。这一机制允许开发者在声明函数之前调用该函数。
/*** 正确的方式:先声明函数,再调用函数 (最佳实践)*/
function catName(name) {
console.log("我的猫名叫 " + name);
}
catName("Tigger");
/*以上代码的执行结果是: "我的猫名叫 Tigger"*/
/*** 不推荐的方式:先调用函数,再声明函数 */
catName("Chloe");
function catName(name) {
console.log("我的猫名叫 " + name);
}
/*代码执行的结果是: "我的猫名叫 Chloe"*/
变量提升的具体规则与行为
提升规则
- 使用 var 声明的变量,在提升过程中仅进行声明而不赋值,默认值为 undefined;若不使用关键字直接赋值,则不存在提升机制(参考 demo1)。
- 函数声明会连带函数体一起提升,但不会立即执行(参考 demo2)。
- 预解析的顺序是从上到下进行的(参考 demo4)。
- 函数的优先级高于变量,函数声明会被提前到当前作用域的最顶端(参考 demo3)。
- 当变量重名时,提升阶段不会重复定义;但在执行阶段,后面赋值的值会覆盖前面的赋值(参考 demo4)。
- 当函数重名时,提升阶段后面的声明会覆盖前面的声明(参考 demo5)。
- 当函数和变量重名时,提升阶段优先提升函数,变量不会覆盖函数;但在执行阶段,后面赋值的值会覆盖上面的赋值(参考 demo8)。
- 使用函数表达式声明函数时,会按照声明变量的规则进行提升(参考 demo6)。
- 函数执行时,其内部的变量声明和函数声明也遵循上述提升规则(参考 demo7)。
- let 和 const 声明的变量不存在提升现象(参考 demo9、demo10)。
/**demo1**/
console.log('a=',a) //a=undefined
console.log('b=',b) // Uncaught ReferenceError: b is not defined
var a=1
b=6
/**deom2**/
console.log('a=',a) // a=function a() {console.log("func a()")}
function a() {
console.log("func a()")
}
/**deom3**/
console.log('a=',a) // a=function a() {console.log("fun a")}
var a=3
var a=4
function a(){
console.log("fun a")
}
var a=5
var a=6
console.log("a=",a) // a=6
/**deom4**/
console.log('a=',a) // a=undefined
var a =2
console.log('a=',a) //
var a =3
var a =4
console.log('a=',a) // a=4
console.log('b=',b) //b= undefined
var b='b1'
/**deom5**/
console.log('a=',a) // a=function a() {console.log("a2")}
function a(){
console.log("a1")
}
function a(){
console.log("a2")
}
console.log('a=',a) // a=function a() {console.log("a2")}
/**deom6**/
console.log('a=',a) // a=undefined
var a=function(){console.log('a1')}
var a=3
var a=4
var a=5
console.log(a)
var a=function(){console.log('a2')}
console.log('a=',a) // a= ƒ (){console.log('a2')}
/**deom7**/
console.log('b=',b)
var a=3
function b(i){
console.log('a=',a)
var a=4
function a(){
console.log('fun a')
}
console.log('a=',a)
}
b()
/**demo8**/
console.log('a=',a) //a= function a(){ console.log('fun a')}
var a=2
function a(){
console.log('fun a')
}
console.log('a=',a) // a=2
var a=3
var a=4
var a=5
console.log('a=',a) // a=5
/**demo9**/
console.log('a=',a) //Uncaught ReferenceError: a is not defined
let a=4
/****/
<!--demo10-->
console.log('b=',b) // Uncaught ReferenceError: b is not defined
const b=5
参考资料
MDN
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。