JavaScript变量提升与执行机制深度解析

作者:木棉时间:2026-10-25 17:33:55浏览:150

本文深入解析JavaScript引擎的执行流程,重点阐述变量提升(Hoisting)与函数声明的提升行为。通过对比var声明与function定义在编译阶段的表现,揭示执行上下文中变量环境对象的创建过程。文章详细分析了重复声明的覆盖规则、undefined值的来源以及全局与函数执行上下文的生命周期,帮助开发者理解代码实际运行顺序与预期差异的根本原因。

变量提升

为深入理解变量提升机制,我们先分析以下代码片段:

        showName()
        console.log(myname)
        var myname = '测试'
        function showName() {
            console.log('函数showName被执行');
        }

运行上述代码后,预期结果是什么?

按常规逻辑推演,执行第1行时,因函数showName尚未定义,预期会报错;同理,第2行引用未定义的变量myname也应报错。然而实际运行并未报错,且成功打印了结果。

变量提升

这与预期不符。是否意味着在JavaScript中,未定义的变量和方法可直接使用?我们将注释掉myname的定义后重新运行代码以观察结果。

变量提升

结果表明,在JavaScript中,变量或函数仍需定义后方可使用。

接下来观察以下代码的执行结果:

        showName()
        console.log('1: ',myname)
        var myname = '测试'
        console.log('2F: ',myname)
        function showName() {
            console.log('函数showName被执行');
        }

变量提升

由此可知,在JavaScript中:

1、若在执行过程中使用未声明的变量,JavaScript引擎会抛出错误。

2、在变量定义前使用它,不会报错,但该变量的值将为undefined,而非定义时的值。

3、在变量定义后使用它,其值为定义时的值。

4、在函数定义前使用它,不会报错,且函数能正常执行。

为何变量和函数在定义前使用不报错?这涉及JavaScript中的变量提升机制。

JavaScript中的声明与赋值:

语句varmyname = '测试'可拆解为变量声明与赋值两个步骤。

声明阶段:

var myname

赋值阶段:

myname = '测试'

函数的声明与赋值:

声明阶段:

function(){

console.log('函数showName被执行');

}

赋值阶段:

var showName = function(){

console.log('函数showName被执行');

}

补充说明:

函数先声明变量showName,再将function(){console.log('函数showName被执行');}赋值给showName。

变量提升是指在JavaScript代码执行过程中,JavaScript引擎将变量声明和函数声明部分提升至代码开头的一种行为。提升后,变量默认值为undefined。这也解释了为何第一段代码中myname打印值为undefined。

因此,第一段代码可理解为:

变量提升

JavaScript代码执行流程

从字面意义看,“变量提升”意味着变量和函数声明在物理层面移动至代码最前端,如我们模拟的那样。但这并不准确。实际上,变量和函数声明在代码中的位置不变,而是在编译阶段由JavaScript引擎放入内存。

代码执行分为编译阶段与执行阶段。

编译阶段

基于上述理解,代码可分为变量提升部分与可执行部分。

变量提升部分的代码:

var myname = undefined
function showName() {
    console.log('函数showName被执行');
}

执行部分的代码:

showName()
console.log(myname)
myname = '极客时间'

代码经编译后生成两部分内容:执行上下文与可执行代码。

变量提升

执行上下文是JavaScript执行代码时的运行环境。例如调用函数时,会进入该函数的执行上下文,确定执行期间使用的this、变量、对象及函数等。

执行上下文中存在一个变量环境对象(Variable Environment),该对象保存变量提升的内容。例如上述代码中的变量myname和函数showName均保存于此对象中。

接下来,我们逐行分析变量环境对象的生成过程:

第1行和第2行因非声明操作,JavaScript引擎不做处理;

第3行经var声明,JavaScript引擎在环境对象中创建名为myname的属性,并用undefined初始化;

第4行JavaScript引擎发现通过function定义的函数,将其定义存储至堆(HEAP)中,并在环境对象中创建showName属性,指向堆中函数位置(若不了解堆也无妨,JavaScript的执行堆和执行栈将在后续文章介绍)。至此生成变量环境对象。随后,JavaScript引擎将声明以外的代码编译为字节码。

执行阶段

我们逐行分析执行过程:

(1)当执行到showName函数时,JavaScript引擎开始在变量环境对象中查找该函数。因对象中存在该函数引用,引擎开始执行该函数,并输出“函数showName被执行”。

(2)接下来打印“myname”信息,JavaScript引擎继续在变量环境对象中查找。因对象中存在myname变量且值为undefined,故输出undefined。

(3)接着执行第3行,将“极客时间”赋值给myname变量。赋值后,变量环境中的myname属性值变为“极客时间”。

代码中出现相同变量或函数怎么办

function showName() {
    console.log('极客邦');
}
showName();
function showName() {
    console.log('极客时间');
}
showName(); 

上述代码的输出结果是什么?

变量提升

我们分析其完整执行流程:

(1)首先是编译阶段。遇到第一个showName函数,将其函数体存入变量环境。接着遇到第二个showName函数,继续存入变量环境。因变量环境中已存在showName函数,第二个showName函数将覆盖第一个。此时变量环境中仅存第二个showName函数。

(2)接下来是执行阶段。先执行第一个showName函数,但因从变量环境中查找showName函数,而环境中仅保存第二个showName函数,故最终调用第二个函数,打印内容“极客时间”。第二次执行showName函数流程相同,输出结果亦为“极客时间”。综上,若代码定义两个同名函数,最终生效的是最后一个函数。

        console.log('1:', myname)
        var myname = 'zhangsan'
        console.log('2:', myname)
        var myname = 'lisi'
        console.log('3:', myname)

上述代码的执行结果又是怎样的?

变量提升

分析:

(1)编译阶段。遇到第一个var myname时,将该变量存入变量环境,值为undefined。接着遇到第二个var myname时,继续存入变量环境,值亦为undefined。因变量环境中已存在myname变量,第二个myname将覆盖第一个。此时变量环境中仅存第二个myname变量,值为undefined。

(2)执行阶段。执行第一个console打印时,myname值为undefined,故打印undefined。直接对myname赋值,值为zhangsan,故执行第二个console时,打印zhangsan。接着执行第二条赋值语句,myname被赋值为lisi,故在执行第三个console时,打印lisi。

何种情况下会进行编译并创建执行上下文?

1、当JavaScript执行全局代码时,会编译全局代码并创建全局执行上下文。整个页面生命周期内,全局执行上下文仅有一份。

2、当调用函数时,函数体内代码会被编译,并创建函数执行上下文。一般情况下,函数执行结束后,创建的函数执行上下文会被销毁。

3、当使用eval函数时,eval代码会被编译,并创建执行上下文。

至此,关于Javascript浅析执行机制的详情文章介绍完毕。更多相关Js执行机制内容请搜索本站以前的文章或继续浏览下面的相关文章,希望大家以后多多支持本站!

作者最新文章