全局执行上下文在脚本加载完成的第一时间自动创建且仅一次,创建阶段扫描并提升var/function/let/const声明,执行阶段逐行运行代码;模块脚本例外,不挂载window、顶层this为undefined、具独立作用域。

全局执行上下文在浏览器中不是“运行时才建”,而是在 <script></script> 标签内容加载完成、引擎开始解析 JS 代码的**第一时间自动创建**,且只发生一次。它不依赖 DOM 是否就绪,也不等你写第一行可执行语句——只要脚本被加载进引擎,初始化流程就立刻启动。
创建阶段:环境与绑定先行
这个阶段不执行任何代码,只做三件关键准备:
- 生成词法环境(LexicalEnvironment)和变量环境(VariableEnvironment),二者初始都指向同一个全局环境记录
- 将 this 绑定为 window 对象(非严格模式下);严格模式下为 undefined
- 扫描整个脚本块,登记所有声明: • var 声明 → 在变量环境中设为 undefined • function 声明 → 完整函数对象直接挂载到 window 上(可提前调用) • let/const 声明 → 仅注册进词法环境,不赋值,处于“暂时性死区”(TDZ)
多个脚本如何参与同一轮初始化
HTML 中按顺序出现的 <script></script> 标签,会依次加载并**统一纳入本轮全局上下文的创建阶段**:
- 第一个 <script></script> 加载完,引擎立即扫描其中的 var/function/let/const,并完成上述绑定
- 第二个 <script></script> 加载完,继续扫描、提升、挂载——它能看到前一个脚本中已提升的 function 和已声明的 var(哪怕还没赋值)
- 动态插入的 script(如 document.createElement('script'))会触发独立的加载和初始化流程,不共享本轮上下文
执行阶段:从上到下真正跑起来
创建阶段一结束,引擎立刻进入执行阶段,逐行处理语句:
- var a = 1 → 此时 a 已存在(值为 undefined),现在只是把它改为 1
- let b = 2 → 解除 TDZ,完成初始化;若在 let 前访问 b,报 ReferenceError
- func() 调用 → 暂停当前上下文,创建并压入新的函数执行上下文
- 顶层 window.x = 1 或直接赋值 x = 1(非严格模式)→ 可能映射为全局对象属性,与 var x 行为一致
注意模块脚本的例外情况
带 type="module" 的脚本不走传统全局上下文流程:
- 不会把变量自动挂到 window 上
- 顶层 this 是 undefined(即使非严格模式)
- 每个模块有自己独立的词法作用域,import/export 决定执行顺序,而非 HTML 顺序











