thisbinding是函数执行上下文内由调用方式即时写入的只读字段,其值取决于调用模式:直接调用按严格模式设为undefined或全局对象,隐式绑定取点号左侧对象,new/call/apply/bind强制指定,箭头函数则静态捕获外层普通函数的thisbinding值。

函数执行上下文的最底层存储架构,本质是调用栈中每个执行上下文对象(Execution Context)内部维护的一个 thisBinding 字段。它不是从作用域链或词法环境继承来的,而是在函数被调用时、进入执行阶段前,由调用方式(Call Site)**即时计算并写入**的只读属性。理解 this 的核心,就是理解这个字段在不同调用模式下被赋值的确定性规则——而非“指向谁”,而是“被设成什么”。
直接调用(Simple Call):严格模式下 this 是 undefined,非严格模式下是全局对象
当函数以 fn() 形式独立调用(无任何上下文修饰),引擎会把 thisBinding 设为:
- 严格模式:
undefined(不可写,不会自动装箱) - 非严格模式:全局对象(浏览器是
window,Node.js 是globalThis)
⚠️ 避坑:箭头函数没有自己的 thisBinding,它沿外层普通函数的 thisBinding 值静态捕获(即定义时所在词法作用域中最近一层普通函数的 this 值),不是继承、也不是查找,是编译期固化。所以 setTimeout(() => this.x, 100) 中的 this 取决于箭头函数写在哪一层函数里,和 setTimeout 调用无关。
隐式绑定(Implicit Binding):点号左侧对象决定 thisBinding
当调用形如 obj.method() 时,引擎提取点号左侧的对象(obj)作为 thisBinding。关键在于:只看调用时的直接左值,不看函数定义位置或是否被赋值变量。
-
const fn = obj.method; fn();→ thisBinding 是全局对象(或 undefined),不是 obj(因为调用时已脱离 obj) -
(obj.method)();→ 等价于obj.method(),thisBinding 是 obj(括号不改变左值) -
(false || obj.method)();→ 左值是 obj.method 的返回值(函数本身),但调用时无主语,属于 Simple Call
⚠️ 避坑:“隐式丢失”本质是函数被抽取后变成 Simple Call。修复方式不是改函数,而是绑定上下文:用 .bind(obj)、obj.method.bind(obj)、const bound = () => obj.method()(箭头函数闭包捕获 obj),或使用 class 字段语法 + 箭头函数(自动绑定实例)。
New 绑定与 call/apply/bind:优先级最高,强制覆盖 thisBinding
这三类操作在函数调用前直接指定 thisBinding,跳过隐式/默认规则:
-
new Fn():创建新对象,把 thisBinding 设为该新对象,并将该对象作为原型链起点 -
fn.call(obj, ...args)/fn.apply(obj, args):立即执行,把 obj 写入 thisBinding -
fn.bind(obj):返回新函数,其 thisBinding 永远固定为 obj(即使后续再 call 或 new,也仅在 new 时被忽略)
⚠️ 避坑:bind 返回的函数无法被 new 正常构造(会忽略绑定的 this,但保留原型链),且多次 bind 只有第一次生效;call/apply 传 null/undefined 在非严格模式下会被自动替换为全局对象,严格模式下就真是 null/undefined。
词法 this 不是 this:箭头函数与 class 字段的本质差异
箭头函数没有 thisBinding 字段,它的 this 是词法引用,编译时记下外层第一个普通函数的 thisBinding 值,之后永不改变。而 class 中的 method = () => {} 字段,本质是构造函数中为每个实例赋值一个箭头函数,该箭头函数捕获的是构造时的 this(即当前实例),所以天然绑定。
- 错误认知:“箭头函数继承外层 this” → 实际是“复用外层函数执行时已确定的 thisBinding 值”
- class 中普通方法
method() {}仍是普通函数,仍受隐式绑定影响;只有字段语法 + 箭头函数才规避 this 丢失 - 不要用箭头函数做构造函数(语法报错),也不要期望它响应
call改变 this(无效)
真正可靠的 this 控制,靠的是明确的调用形式(obj.fn())、显式绑定(bind/call/apply)或词法固化(箭头函数 + 合理定义位置)。所有“意外”都源于混淆了调用时的左值、函数提取过程、以及绑定时机的先后顺序。











