如何理解javascript的执行上下文【教程】

3次阅读

javaScript执行上下文分全局、函数、eval三种,仅在全局执行、函数调用、eval执行时创建;每个上下文含variableEnvironment、LexicalEnvironment和this绑定三部分。

如何理解javascript的执行上下文【教程】

javascript 的执行上下文不是抽象概念,而是真实存在的、可推导的运行时结构——它决定了变量和函数在哪儿能被访问、值是什么、this 指向谁。理解它,关键不是背定义,而是看代码执行时“引擎到底做了什么”。

执行上下文分哪几种?什么时候创建?

js 引擎只在三种时刻新建执行上下文:

  • 全局代码开始执行时 → 创建 Global Execution Context
  • 调用一个函数时 → 创建新的 function Execution Context
  • 执行 eval()(不推荐)时 → 创建 Eval Execution Context

注意:iffor{} 块级作用域不会创建执行上下文,它们只影响词法环境(Lexical Environment),但不触发上下文

每个执行上下文内部有哪三块核心数据?

每个上下文都包含三个关键部分,且按固定顺序初始化:

立即学习Java免费学习笔记(深入)”;

  • VariableEnvironment:存放 var 声明、函数声明(会被提升)、function 参数 —— 这是真正参与变量提升(hoisting)的部分
  • LexicalEnvironment:存放 letconstclass 声明(暂存性死区 TDZ 就发生在这里);在函数中,它通常初始时与 VariableEnvironment 相同,但后续可能分离(比如遇到 withcatch 绑定)
  • this 绑定:由调用方式决定,不是由声明位置决定 —— obj.fn()thisobj,而 fn() 独立调用时在非严格模式下是 window(或 globalThis),严格模式下是 undefined

为什么 setTimeout 里的函数总拿不到最新值?跟执行上下文有关吗?

有关,但不是因为“闭包捕获了旧上下文”,而是因为:每次循环迭代都会创建**新的词法环境**(LexicalEnvironment),而 setTimeout 回调在将来执行时,会通过作用域链向上查找——它找的是自己被定义时所在那次迭代的环境,而不是最后一次。

典型例子:

for (var i = 0; i < 3; i++) {   setTimeout(() => console.log(i), 0); // 输出 3, 3, 3 }

原因:var 声明绑定在 VariableEnvironment 上,整个循环共用一个 i;而改成 let 就输出 0,1,2,因为 let 每次迭代都生成新绑定,对应新 LexicalEnvironment

调试时怎么看当前执行上下文?

浏览器 DevTools 不直接显示“执行上下文对象”,但你可以间接观察它的行为:

  • 断点停住后,在 “Scope” 面板里看到的 “Closure”、“Script”、“Global” 就是当前上下文的 LexicalEnvironment
  • 展开 “Local” 可见当前函数的参数和 let/const 变量;“Script” 显示当前脚本级的 var 和函数声明
  • 右键变量 → “Re-evaluate in console”,可验证该变量是否处于 TDZ(报 ReferenceError: Cannot access 'x' before initialization

真正的难点不在识别上下文存在,而在于意识到:函数体内的自由变量,查的是它**定义时**所处的词法环境链,不是**执行时**所处的调用栈——这个错位,是绝大多数闭包误解和 this 失控的根源。

text=ZqhQzanResources