this 的本质
执行上下文(Execution Context)到底是什么?[[LexicalEnvironment]] 和 this 是怎么共存的?
一、执行上下文的本质:一个抽象记录(Abstract Record)
根据 ECMA-262 §8.3, 一个执行上下文在规范中被定义为一个包含三个字段的抽象记录:
text
ExecutionContext = {
[[Function]]: Function | null, // 当前正在执行的函数(如果是函数调用)
[[Realm]]: Realm, // 当前代码运行的环境(全局对象、内置对象等)
[[ScriptOrModule]]: Script | Module | null,
[[LexicalEnvironment]]: Lexical Environment, // 👈 词法环境
[[VariableEnvironment]]: Lexical Environment, // 👈 变量环境
[[ThisBinding]]: any // 👈 this 的值
}🔥 所以你完全正确:执行上下文的核心字段之一就是 [[LexicalEnvironment]]!
但这不是说“执行上下文是 [[LexicalEnvironment]]”,而是: 执行上下文“拥有”一个 [[LexicalEnvironment]] 字段,用来管理当前作用域中的变量声明。
二、this 在哪?就在 [[ThisBinding]] 里!
你问得好:“那 this 在这上面吗?”
答案是:在!它就是 [[ThisBinding]]!
| 内部槽 | 含义 |
|---|---|
[[LexicalEnvironment]] | 当前作用域中 let、const、class 等的绑定环境 |
[[VariableEnvironment]] | 当前作用域中 var、函数声明的绑定环境(通常和 [[LexicalEnvironment]] 初始时相同) |
[[ThisBinding]] | 当前上下文中 this 的值 |
所以:this 不是藏在 [[LexicalEnvironment]] 里,而是和它并列的一个独立字段。
三、举个例子:函数执行时发生了什么?
js
const obj = {
name: "Alice",
greet() {
let a = 1;
var b = 2;
console.log(this.name); // Alice
}
};
obj.greet();当 greet() 执行时,引擎创建一个函数执行上下文:
text
{
[[Function]]: greet,
[[Realm]]: 当前全局环境,
[[ScriptOrModule]]: ...,
[[LexicalEnvironment]]: {
// 环境记录(Environment Record):
type: 'object-environment' or 'declarative',
bindings: { a: 1 } // let/const/class
},
[[VariableEnvironment]]: {
bindings: { b: 2 } // var/function declarations
},
[[ThisBinding]]: obj // 👈 this 就是 obj
}所以 this.name 能访问到 "Alice",是因为:
this是[[ThisBinding]]的值(obj)obj.name是对象属性,直接查找
而 a 和 b 是通过 [[LexicalEnvironment]] 和 [[VariableEnvironment]] 查找的。
四、[[ThisBinding]] 是怎么设置的?
它在执行上下文创建阶段根据调用方式确定:
| 调用方式 | [[ThisBinding]] 设置为 |
|---|---|
obj.method() | obj |
fn() | 全局对象(非严格) / undefined(严格) |
new Fn() | 新创建的实例 |
fn.call(ctx) | ctx |
| 箭头函数 | 继承外层上下文的 [[ThisBinding]] |
注意:箭头函数没有自己的 [[ThisBinding]],它直接复用外层的。
五、图解:执行上下文的完整结构
执行上下文 (ExecutionContext)
│
├── [[Function]] → 指向当前执行的函数
├── [[Realm]] → 运行环境(内置对象、全局对象等)
├── [[ScriptOrModule]] → 当前执行的是脚本还是模块
├── [[LexicalEnvironment]]
│ └── 环境记录
│ ├── a: 1 // let/const
│ └── inner: function
│
├── [[VariableEnvironment]]
│ └── 环境记录
│ └── b: 2 // var
│
└── [[ThisBinding]] → obj(或 window, undefined, 实例等)你看,[[LexicalEnvironment]] 和 [[ThisBinding]] 是“兄弟关系”,不是“父子关系”。
六、为什么 this 不放在 [[LexicalEnvironment]] 里?
这是个极好的问题!
原因如下:
语义分离:
[[LexicalEnvironment]]管理的是标识符绑定(变量名 → 值)this不是一个变量名,而是一个执行上下文的状态- 它更像是“当前上下文的配置项”,而不是“可声明的标识符”
查找机制不同:
- 变量查找:沿着作用域链(
[[Environment]]链)向上找 this查找:不走作用域链!它只由调用方式决定jsfunction foo() { console.log(this); // 不是从外层 scope 找来的! }
- 变量查找:沿着作用域链(
性能优化:
this是高频访问的值,引擎可以专门优化[[ThisBinding]]的读取- 如果混在环境记录里,查找效率会下降