JavaScript中的执行上下文与作用域链
字数 1304 2025-11-07 12:34:03

JavaScript中的执行上下文与作用域链

描述
执行上下文(Execution Context)是JavaScript代码执行时的环境,包含变量、函数、作用域链等关键信息。作用域链(Scope Chain)是用于解析变量访问权限的机制,由当前执行上下文和所有外层上下文的变量对象组成。理解这两者有助于掌握变量查找、闭包等核心概念。

步骤1:执行上下文的类型
JavaScript中有三种执行上下文:

  1. 全局执行上下文:代码首次运行时创建,全局唯一,生命周期与程序一致。
  2. 函数执行上下文:每次调用函数时创建,函数执行完毕后销毁。
  3. Eval执行上下文(较少使用):在eval函数内部代码执行时创建。

每个执行上下文包含三个核心组件:

  • 变量对象(Variable Object):存储变量、函数声明和形参。
  • 作用域链(Scope Chain):由当前变量对象和父级作用域链组成。
  • this值:指向当前执行上下文关联的对象。

步骤2:执行上下文的创建过程
以函数执行上下文为例,创建分为两个阶段:

  1. 创建阶段

    • 创建变量对象:
      • 扫描函数参数,添加为属性(值初始为传入值或undefined)。
      • 扫描函数声明,添加为属性(值为函数引用,覆盖同名参数)。
      • 扫描变量声明,添加为属性(值初始为undefined,不覆盖同名函数或参数)。
    • 构建作用域链:复制函数的[[Scope]]属性(定义时确定),并将当前变量对象添加到链首。
    • 确定this绑定(由调用方式决定)。
  2. 执行阶段

    • 逐行执行代码,修改变量对象中的值。
    • 遇到变量时,沿作用域链查找。

示例分析

var a = 1;
function foo(b) {
  var c = 2;
  console.log(a + b + c);
}
foo(3); // 输出6
  • 全局上下文创建阶段

    • 变量对象:a: undefined, foo: <function>
    • 作用域链:[全局变量对象]
    • this指向全局对象(如window)。
  • 全局上下文执行阶段

    • 执行a = 1,修改变量对象为a: 1
    • 执行foo(3),创建函数上下文。
  • foo函数上下文创建阶段

    • 变量对象:b: 3, c: undefined(参数b优先,变量c初始化)。
    • 作用域链:[foo变量对象, 全局变量对象](复制foo.[[Scope]]并添加当前变量对象)。
    • this由调用决定(此处为默认绑定,指向全局对象)。
  • foo函数上下文执行阶段

    • 执行c = 2,修改变量对象为c: 2
    • 执行console.log(a + b + c)
      • 查找a:当前变量对象无a → 沿作用域链查全局变量对象,找到a=1
      • bc直接在当前变量对象中找到。

步骤3:作用域链的形成原理

  • 函数在定义时就确定了[[Scope]]属性,包含其外层作用域的变量对象。
  • 例如,嵌套函数的作用域链在创建时会包含外层函数的变量对象:
function outer() {
  var x = 10;
  function inner() {
    console.log(x); // 通过作用域链访问outer的x
  }
  return inner;
}
var innerFunc = outer(); // outer执行后,inner仍能通过作用域链访问x(闭包)

关键点总结

  1. 执行上下文是动态创建的,而作用域链在函数定义时静态确定。
  2. 变量查找沿作用域链由内向外,找不到则报ReferenceError
  3. 闭包的本质是函数保留了对定义时作用域链的引用,即使外层函数已执行完毕。
JavaScript中的执行上下文与作用域链 描述 执行上下文(Execution Context)是JavaScript代码执行时的环境,包含变量、函数、作用域链等关键信息。作用域链(Scope Chain)是用于解析变量访问权限的机制,由当前执行上下文和所有外层上下文的变量对象组成。理解这两者有助于掌握变量查找、闭包等核心概念。 步骤1:执行上下文的类型 JavaScript中有三种执行上下文: 全局执行上下文 :代码首次运行时创建,全局唯一,生命周期与程序一致。 函数执行上下文 :每次调用函数时创建,函数执行完毕后销毁。 Eval执行上下文 (较少使用):在 eval 函数内部代码执行时创建。 每个执行上下文包含三个核心组件: 变量对象(Variable Object) :存储变量、函数声明和形参。 作用域链(Scope Chain) :由当前变量对象和父级作用域链组成。 this值 :指向当前执行上下文关联的对象。 步骤2:执行上下文的创建过程 以函数执行上下文为例,创建分为两个阶段: 创建阶段 : 创建变量对象: 扫描函数参数,添加为属性(值初始为传入值或 undefined )。 扫描函数声明,添加为属性(值为函数引用,覆盖同名参数)。 扫描变量声明,添加为属性(值初始为 undefined ,不覆盖同名函数或参数)。 构建作用域链:复制函数的 [[Scope]] 属性(定义时确定),并将当前变量对象添加到链首。 确定 this 绑定(由调用方式决定)。 执行阶段 : 逐行执行代码,修改变量对象中的值。 遇到变量时,沿作用域链查找。 示例分析 全局上下文创建阶段 : 变量对象: a: undefined , foo: <function> 作用域链: [全局变量对象] this 指向全局对象(如 window )。 全局上下文执行阶段 : 执行 a = 1 ,修改变量对象为 a: 1 。 执行 foo(3) ,创建函数上下文。 foo函数上下文创建阶段 : 变量对象: b: 3 , c: undefined (参数 b 优先,变量 c 初始化)。 作用域链: [foo变量对象, 全局变量对象] (复制 foo.[[Scope]] 并添加当前变量对象)。 this 由调用决定(此处为默认绑定,指向全局对象)。 foo函数上下文执行阶段 : 执行 c = 2 ,修改变量对象为 c: 2 。 执行 console.log(a + b + c) : 查找 a :当前变量对象无 a → 沿作用域链查全局变量对象,找到 a=1 。 b 和 c 直接在当前变量对象中找到。 步骤3:作用域链的形成原理 函数在 定义时 就确定了 [[Scope]] 属性,包含其外层作用域的变量对象。 例如,嵌套函数的作用域链在创建时会包含外层函数的变量对象: 关键点总结 执行上下文是动态创建的,而作用域链在函数定义时静态确定。 变量查找沿作用域链由内向外,找不到则报 ReferenceError 。 闭包的本质是函数保留了对定义时作用域链的引用,即使外层函数已执行完毕。