JavaScript 执行期上下文 & 闭包
一、执行上下文(Execution Context)
JavaScript 执行代码时,会为每一段可执行代码创建一个 执行上下文,它是代码运行的“环境”。
三种类型
- 全局执行上下文:脚本启动时创建,全局作用域。
- 函数执行上下文:每次调用函数时创建。
- eval 执行上下文:
eval中执行代码时创建(不常用)。
执行上下文的结构
每个执行上下文在运行时包含三个核心部分:
| 组件 | 说明 |
|---|---|
| LexicalEnvironment | 当前上下文的词法环境(管理 let/const) |
| VariableEnvironment | 当前上下文的变量环境(管理 var/函数声明) |
| ThisBinding | this 的值 |
✅ 简记:执行上下文 = 词法环境 + 变量环境 + this
二、词法环境 vs 变量环境
| 名称 | 负责 | 特点 |
|---|---|---|
| LexicalEnvironment | let、const |
有块级作用域,有“暂时性死区”(TDZ) |
| VariableEnvironment | var、函数声明 |
有变量提升,无块级作用域 |
⚠️ 注意:函数开始执行时,
LexicalEnvironment和VariableEnvironment通常相同,但后续可能分离(如eval)。
三、词法环境(Lexical Environment)的内部结构
每个词法环境是一个抽象结构,包含两个部分:
| 部分 | 说明 |
|---|---|
| Environment Record | 存储变量和函数声明的实际位置(如对象环境记录、声明性环境记录) |
| Outer Environment Reference | 指向外层词法环境的引用,形成作用域链 |
✅ 作用域链 = 通过
Outer一级一级向上查找
四、函数的内部属性:[[Environment]]
- 定义:函数对象的一个内部槽(Internal Slot)
- 创建时机:函数定义时自动创建
- 值:指向函数定义时所处的词法环境
- 作用:实现闭包和词法作用域的核心
1 | function outer() { |
✅
[[Environment]]是函数的“出生地记忆”
五、Outer Environment Reference 是谁初始化的?
关键问题:词法环境的
Outer从哪来?
✅ 答案
Outer Environment Reference 是在创建词法环境时,由 JavaScript 引擎根据以下规则自动设置:
| 场景 | Outer 的来源 |
|---|---|
| 函数调用 | 来自函数的 [[Environment]] 属性 |
块级作用域(如 if、for) |
来自当前执行上下文的词法环境(词法嵌套结构) |
🎯 核心流程(函数调用时)
- 调用函数
fn() - 创建
fn的执行上下文 - 创建
fn.LexicalEnvironment - 设置
fn.LexicalEnvironment.Outer = fn.[[Environment]]
✅ 所以:
[[Environment]]是Outer的“源头”
六、闭包(Closure)
1. 什么是闭包?
一个函数能够访问其定义时所在的作用域中的变量,即使该函数在外部执行。
2. 闭包的形成条件
- 内层函数引用了外层函数的变量
- 内层函数被传递到外层函数之外(如返回、赋值)
3. 闭包的本质
闭包 = 函数 + 函数的
[[Environment]]引用
4. 例子
1 | function counter() { |
🔗 原因:
inner.[[Environment]]指向counter的词法环境,count不会被回收。
七、this 的指向
| 函数类型 | this 指向 |
|---|---|
| 普通函数 | 谁调用,谁就是 thisobj.fn() → this = obj |
| 箭头函数 | 继承定义时外层作用域的 this(没有自己的 this) |
| 全局环境 | 浏览器:window,Node.js:global |
✅ 箭头函数的
this是词法绑定,普通函数是动态绑定。
八、变量提升(Hoisting)
| 声明方式 | 是否提升 | 初始化 | 访问时机 |
|---|---|---|---|
var |
✅ 是 | undefined |
声明前可访问 |
let / const |
✅ 声明提升 | 不初始化(TDZ) | 声明前访问报错 |
⚠️
let/const也有“提升”,但不能在声明前使用(暂时性死区)。
九、未声明变量
x = 10→ 自动成为全局变量- 存储位置:全局执行上下文
- 应避免,防止污染全局
十、开发者工具中的观察
| 概念 | 是否可在代码中访问 | 是否可在 DevTools 中观察 |
|---|---|---|
[[Environment]] |
❌ 否 | ❌ 否 |
[[Scopes]] |
❌ 否 | ✅ 是(Chrome 调试用) |
| 执行上下文 | ❌ 否 | ✅ 是(Scope 面板) |
this |
✅ 可通过 console.log(this) |
✅ 是 |
🛠️ DevTools 的
[[Scopes]]是[[Environment]]的调试快照。
🧩 核心图解(文字版)
1 | 函数定义时: |
✅ 总结
- 定义时确定作用域,调用时确定 this
var提升为undefined,let/const有暂时性死区- 闭包是函数 +
[[Environment]][[Environment]]是函数的,Outer是词法环境的Outer的值来自[[Environment]]- 作用域链 =
Outer连成的链- 执行上下文有
LexicalEnvironment和VariableEnvironment,分工明确
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 YianNotes!

