作者:watermelo37 CSDN全栈领域优质创作者、华为云云享专家、阿里云专家博主、腾讯云“创作之星”特邀作者、火山KOL、支付宝合作作者,全平台博客昵称watermelo37。 一个假装是giser的coder,做不只专注于业务逻辑的前端工程师,Java、Docker、Python、LLM均有涉猎。 --------------------------------------------------------------------- 温柔地对待温柔的人,包容的三观就是最大的温柔。 ---------------------------------------------------------------------

小瓜很久以前写过一篇《【最简单最全面】一文讲清楚五大this指向,this到底指向哪里?》,能够通过原理 -> 案例 -> 对比的帮助大家快速学习和辨别各种场景下的 this 指向,有兴趣的读者请移步:【最简单最全面】一文讲清楚五大this指向,this到底指向哪里?
文中详细解释了各种场景下的 this 指向,但只是简单提了提 this 丢失的情况,最近我在开发中就遇到了一个 this 丢失的场景,代码简化如下:
window.identity = 'The Window'
let object = {
identity: 'My Object',
getIdentity () {
return this.identity;
}
};
// 简单思考一下,1和2的返回分别是什么?
(object.getIdentity()); // 1
(object.getIdentity = object.getIdentity)(); // 2猜出答案不难,首先1肯定是My Object,如果对这个有疑问建议先点击上述链接前往了解,那2是什么呢?既然提到了 this 丢失,那2的this肯定会变,那就只能是The Window 了,可是为什么呢?
首先 (object.getIdentity()) 这是一个典型的作为对象方法调用,所以 this → object 。获取到的值即为“My Object”。
但第二个:(object.getIdentity = object.getIdentity)() 在赋值运算符执行后,返回的是右侧的值,也就是那个函数本身。换句话说,这行代码等价于:
let temp = object.getIdentity; // 赋值表达式
(temp)(); // 调用表达式temp() 是普通函数调用,其 this 默认指向全局对象(浏览器下为 window)。于是就得到了结果 2:“The Window”。
在Js中,除了箭头函数(箭头函数的this在定义的时候就确定下来了,并且无法修改)外的函数 this 绑定,都是取决于调用的方式而不是定义的方式。大致规则如下:
// 因此会把 obj 设为 this
(obj.method)()
// 但是这个就就不再有 obj 参与,结果 this → window。
(let tmp = obj.method; tmp)()核心原因在于:赋值表达式的返回值是“右侧的值本身”,不保留任何引用信息。
object.getIdentity = object.getIdentity
// 上面语句的结果只是一个函数对象,而不携带其他的信息
function getIdentity() { ... }而方法调用为什么能绑定 this?因为属性访问表达式会产生一个带有 base 对象的 “Reference 类型”。这样就可以追溯方法调用方的其他属性,最后获取具体的 this 指向。
语言规范中有一个关键术语:Reference 类型(只存在于规范,不可直接访问)
当你写出:object.getIdentity 它并不是简单取值,而是生成一个 Reference { base: object, name: 'getIdentity' } 当你使用括号调用:(object.getIdentity)() 规范执行的是:Call(F, thisArgument = Reference.base)
这样就会保留 this = object 的引用信息,但赋值表达式会破坏 Reference 信息。
(object.getIdentity = object.getIdentity) 左边的 object.getIdentity 是一个 Reference,右边是函数值,赋值表达式把右侧值写入左侧,返回值为函数本身,不带 Reference Base。
于是就变成了普通函数调用 → this 指向 window。
赋值过程丢失this 的核心原因主要是以下两点:
①赋值表达式的返回值是“右侧值本身” → 丢失了 base 信息
(object.getIdentity = object.getIdentity) ↓ 返回的是函数本身,而非“带 base 的引用”
②() 运算符的 this 绑定取决于“调用表达式的结构”,而不是函数来源
(someFunction)() 因为没有附带 base → 普通函数调用 → this = window。
通过这个案例,我们看到 this 并不是“跟着函数走的”,而是“跟着调用表达式走的”。一旦你把方法从对象上“拿出来”,它就不属于那个对象了,this 自然也就丢了。理解了这点,就能彻底理解非常多 this 丢失的问题,包括 React、class 绑定、事件回调、计时器、解构赋值、对象方法传递等各种场景。
只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~