为什么赋值过程会丢失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操作等

相关推荐
Lsir10110_15 分钟前
从按钮“点不动“讲起——深入理解 Qt 信号槽机制
开发语言·qt·信号处理
君科程序定做17 分钟前
用 IDL 处理高分一号(GF-1 / GF-1B/C/D)数据
c语言·开发语言
敲代码的嘎仔19 分钟前
用 Redis 合并写 + DelayQueue 延迟检测,把视频播放进度写库频率降到 1/60
java·开发语言·数据库·redis·缓存·音视频·高并发
代码中介商1 小时前
C++ 预约系统实战(一):项目总览与 C/S 架构设计
c语言·开发语言·c++
一拳不是超人1 小时前
一个没测暗色模式的 Bug,吃掉了我一半 谷歌扩展用户
前端·javascript·程序员
我叫汪枫1 小时前
RAG 进阶:切分、检索、重排序,以及它和 Agent、微调、MCP 都是什么关系
开发语言·python
弘毅 失败的 mian1 小时前
数组和指针基础
c语言·开发语言·经验分享·笔记
liangshanbo12151 小时前
React useState 函数式更新面试题整理
前端·react.js·前端框架
涛涛ing1 小时前
为什么你的页面在 Safari 上总出问题?Interop 2027 正在解决这个 20 年老毛病
前端
ai小陈1 小时前
Python 3.12与CUDA 12.8镜像实战:启动GPU实例后的五项自检
开发语言·人工智能·python·深度学习·ai·gpu算力