为什么赋值过程会丢失this

目录

为什么赋值过程会丢失this

一、场景重现

二、复现问题:同一个函数,不同调用方式

1、问题解答

2、Js中this绑定取决于调用方式

[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的用法详解

Web Worker:让前端飞起来的隐形引擎

测评:这B班上的值不值?在不同城市过上同等生活水平到底需要多少钱?

通过array.filter()实现数组的数据筛选、数据清洗和链式调用

DeepSeek:全栈开发者视角下的AI革命者

TreeSize:免费的磁盘清理与管理神器,解决C盘爆满的燃眉之急

通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能

高效工作流:用Mermaid绘制你的专属流程图;如何在Vue3中导入mermaid绘制流程图

通过MongoDB Atlas 实现语义搜索与 RAG------迈向AI的搜索机制

深入理解 JavaScript 中的 Array.find() 方法:原理、性能优势与实用案例详解

前端实战:基于Vue3与免费满血版DeepSeek实现无限滚动+懒加载+瀑布流模块及优化策略

【前端实战】如何让用户回到上次阅读的位置?

el-table实现动态数据的实时排序,一篇文章讲清楚elementui的表格排序功能

JavaScript双问号操作符(??)详解,解决使用 || 时因类型转换带来的问题

内存泄漏------海量数据背后隐藏的项目生产环境崩溃风险!如何避免内存泄漏

MutationObserver详解+案例------深入理解 JavaScript 中的 MutationObserver

JavaScript中通过array.map()实现数据转换、创建派生数组、异步数据流处理、DOM操作等

相关推荐
~无忧花开~3 小时前
JavaScript实现PDF本地预览技巧
开发语言·前端·javascript
靠沿3 小时前
Java数据结构初阶——LinkedList
java·开发语言·数据结构
4***99743 小时前
Kotlin序列处理
android·开发语言·kotlin
froginwe113 小时前
Scala 提取器(Extractor)
开发语言
t***D2643 小时前
Kotlin在服务端开发中的生态建设
android·开发语言·kotlin
一 乐3 小时前
宠物管理|宠物共享|基于Java+vue的宠物共享管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·springboot·宠物
小时前端3 小时前
“能说说事件循环吗?”—— 我从候选人回答中看到的浏览器与Node.js核心差异
前端·面试·浏览器
Want5954 小时前
C/C++跳动的爱心②
c语言·开发语言·c++
IT_陈寒4 小时前
Vite 5.0实战:10个你可能不知道的性能优化技巧与插件生态深度解析
前端·人工智能·后端