JavaScript 执行上下文详解:变量提升、作用域与闭包底层原理

青禾
青禾
发布时间:2026-10-15 | 4人浏览过
原创

执行上下文是 JavaScript 代码运行的环境核心,承载着变量存储、作用域链规则及 this 指向。从编译阶段的变量提升到运行时的作用域链查找,再到闭包的内存回收,本文通过代码实例逐一拆解其底层原理。

执行上下文概述

执行上下文(Execution Context)是 JavaScript 代码执行的环境,负责管理代码执行所需的变量、变量查找的作用域链规则以及 this 的指向。它是理解变量提升、作用域链和闭包等难点的基础。

根据代码类型,执行上下文主要分为三类:

  • 全局执行上下文:进入全局代码时编译生成,生命周期伴随页面始终。
  • 函数执行上下文:执行过程中遇到函数调用时创建并压入栈中,函数执行完毕后弹出销毁。
  • Eval 执行上下文:使用 eval 函数时单独创建的上下文。

由于上下文是在编译阶段创建的,我们需要先了解 JavaScript 代码的执行流程。

JavaScript 代码的执行过程

JavaScript 引擎将代码按“段”进行编译和执行,包括全局代码段和函数代码段。每进入一个新的代码段,都会经历编译和执行两个阶段。

第1步:编译阶段

此阶段主要完成两件事:创建执行上下文和生成可执行代码。

  1. 创建执行上下文:建立变量环境和词法环境。
    - 普通变量:var 声明的变量添加到变量环境中,初始化为 undefined。
    - 函数声明:function 定义的函数直接加入变量环境,函数名指向内存中的函数对象。
  2. 生成可执行代码:将其他代码编译为字节码,准备执行。

第2步:执行阶段

引擎按行执行可执行代码: - 读取变量时,在变量环境中寻找;若未找到且非赋值操作,则报错。
- 遇到赋值语句时,将值存入对应的变量中。

变量提升与 ES6 新特性

变量提升是指 JS 引擎在编译阶段将变量的声明部分提取到当前作用域顶部的行为。这并非物理移动代码位置,而是内存管理的结果。

第1步:区分 var、let 和 const

var 声明存在变量提升,默认赋值为 undefined。而 let 和 const 不存在提升行为,且在未初始化前不可访问(暂时性死区),支持块级作用域。

console.log(fn);  // [Function: fn]
console.log(a);   // undefined
function fn() {
    console.log(111);
}
var a = 1;

在此例中,函数声明优先级高于普通变量。当有多个同类型声明时,后面的会覆盖前面的;函数声明优先于 var 变量声明。

第2步:词法环境的栈结构实现

对于包含块级作用域的函数,let/const 会被放入词法环境栈中。块开始时将变量压入栈,块结束时弹出。

function foo(){
    var a = 1;
    let b = 2;
    {
      let b = 3;
      var c = 4;
      let d = 5;
      console.log(a); // 1
      console.log(b); // 3
    }
    console.log(b); // 2 (c已出块级作用域)
    console.log(c); // 4
}

变量查找与作用域链

变量查找遵循“词法环境栈顶向下”的规则。若在当前位置找不到变量,则通过外部引用 outer 向上一级执行上下文查找,直到找到或到达全局作用域。

第1步:理解词法作用域

词法作用域由函数声明的位置决定,而非调用的位置。这使得内部函数能固定地访问外部函数的变量。

调用栈与闭包机制

调用栈(Call Stack)用于管理函数调用关系。每次函数调用创建新的执行上下文压入栈顶,执行完毕后弹出。栈容量有限,深层递归可能导致栈溢出。

第1步:闭包的定义与表现

闭包是指内部函数引用了外部函数的变量,即使外部函数执行结束,这些变量依然保存在内存中。

function foo() {
    var myName = "极客时间";
    return {
        getName: function(){ return myName; },
        setName: function(newName){ myName = newName; }
    };
}
var bar = foo();
bar.setName("极客邦");
console.log(bar.getName()); // 极客邦

第2步:闭包中的变量查找路径

在修改闭包内变量时,JS 引擎沿“当前上下文 → 外部闭包 → 全局上下文”的顺序查找目标变量。

第3步:闭包的内存回收

不当使用闭包易导致内存泄漏。全局引用的闭包只有页面关闭时释放;局部引用的闭包在函数销毁后,若不再被引用,垃圾回收器将回收其占用的内存。建议将不常使用的大体积闭包变量设为局部变量并及时置空。

执行上下文中的 this 指向

this 的值取决于当前的执行上下文:

  • 全局上下文中 this 指向全局对象。
  • 普通函数中 this 根据调用方式(隐式、显式、new 绑定等)确定。
  • 箭头函数没有独立的执行上下文,其 this 继承自外层最近的执行上下文。

以上就是 JavaScript 执行上下文的详细内容,更多关于 JavaScript 执行机制、作用域及内存管理的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表