目录
[3、为什么赋值表达式会导致 this 的丢失?](#3、为什么赋值表达式会导致 this 的丢失?)
[三、ECMAScript 规范层面的解释](#三、ECMAScript 规范层面的解释)
作者:watermelo37
CSDN全栈领域优质创作者、华为云云享专家、阿里云专家博主、腾讯云"创作之星"特邀作者、火山KOL、支付宝合作作者,全平台博客昵称watermelo37。
一个假装是giser的coder,做不只专注于业务逻辑的前端工程师,Java、Docker、Python、LLM均有涉猎。
温柔地对待温柔的人,包容的三观就是最大的温柔。
为什么赋值过程会丢失this

一、场景重现
小瓜很久以前写过一篇《【最简单最全面】一文讲清楚五大this指向,this到底指向哪里?》,能够通过原理 -> 案例 -> 对比的帮助大家快速学习和辨别各种场景下的 this 指向,有兴趣的读者请移步:【最简单最全面】一文讲清楚五大this指向,this到底指向哪里?
文中详细解释了各种场景下的 this 指向,但只是简单提了提 this 丢失的情况,最近我在开发中就遇到了一个 this 丢失的场景,代码简化如下:
javascript
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 了,可是为什么呢?
二、复现问题:同一个函数,不同调用方式
1、问题解答
首先 (object.getIdentity()) 这是一个典型的**作为对象方法调用,**所以 this → object 。获取到的值即为"My Object"。
但第二个:(object.getIdentity = object.getIdentity)() 在赋值运算符执行后,返回的是右侧的值,也就是那个函数本身。换句话说,这行代码等价于:
javascript
let temp = object.getIdentity; // 赋值表达式
(temp)(); // 调用表达式
temp() 是普通函数调用,其 this 默认指向全局对象(浏览器下为 window)。于是就得到了结果 2:"The Window"。
2、Js中this绑定取决于调用方式
在Js中,除了箭头函数(箭头函数的this在定义的时候就确定下来了,并且无法修改)外的函数 this 绑定,都是取决于调用的方式而不是定义的方式。大致规则如下:
- obj.fn() → this = obj
- fn() → this = window 或 undefined(严格模式)
- new fn() → this = 新对象
- fn.call(obj) → this = obj
- obj.fn.bind(obj) → this 永久绑定 obj
javascript
// 因此会把 obj 设为 this
(obj.method)()
// 但是这个就就不再有 obj 参与,结果 this → window。
(let tmp = obj.method; tmp)()
3、为什么赋值表达式会导致 this 的丢失?
核心原因在于:赋值表达式的返回值是"右侧的值本身",不保留任何引用信息。
javascript
object.getIdentity = object.getIdentity
// 上面语句的结果只是一个函数对象,而不携带其他的信息
function getIdentity() { ... }
而方法调用为什么能绑定 this?因为属性访问表达式会产生一个带有 base 对象的 "Reference 类型"。这样就可以追溯方法调用方的其他属性,最后获取具体的 this 指向。
三、ECMAScript 规范层面的解释
语言规范中有一个关键术语: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 绑定、事件回调、计时器、解构赋值、对象方法传递等各种场景。
只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
其他热门文章,请关注:
极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图
你真的会使用Vue3的onMounted钩子函数吗?Vue3中onMounted的用法详解
测评:这B班上的值不值?在不同城市过上同等生活水平到底需要多少钱?
通过array.filter()实现数组的数据筛选、数据清洗和链式调用
TreeSize:免费的磁盘清理与管理神器,解决C盘爆满的燃眉之急
通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能
高效工作流:用Mermaid绘制你的专属流程图;如何在Vue3中导入mermaid绘制流程图
通过MongoDB Atlas 实现语义搜索与 RAG------迈向AI的搜索机制
深入理解 JavaScript 中的 Array.find() 方法:原理、性能优势与实用案例详解
前端实战:基于Vue3与免费满血版DeepSeek实现无限滚动+懒加载+瀑布流模块及优化策略
el-table实现动态数据的实时排序,一篇文章讲清楚elementui的表格排序功能
JavaScript双问号操作符(??)详解,解决使用 || 时因类型转换带来的问题
内存泄漏------海量数据背后隐藏的项目生产环境崩溃风险!如何避免内存泄漏
MutationObserver详解+案例------深入理解 JavaScript 中的 MutationObserver
