游乐游手机版
首页/前端开发/文章详情

Object.assign 拷贝访问器属性的处理机制

时间:2026-07-03 06:54
你可能觉得 Object assign 只是个简单的“复制”工具,把源对象的属性一股脑搬到目标对象上就完事。但事实上,它对访问器属性(即通过 get set 定义的属性)的处理方式,远没有你想象的那么“智能”。直白点说,它只复制属性值,不会复制“行为”——这正是许多 JavaScript 开发者容易
你可能觉得 Object.assign 只是个简单的“复制”工具,把源对象的属性一股脑搬到目标对象上就完事。但事实上,它对访问器属性(即通过 get/set 定义的属性)的处理方式,远没有你想象的那么“智能”。直白点说,它只复制属性值,不会复制“行为”——这正是许多 JavaScript 开发者容易踩坑的地方。

Ja vaScript 中 Object.assign 在拷贝过程中对访问器属性的处理

先明确一个核心结论:Object.assign 在拷贝过程中,既不会调用源对象上的 getter,也不会在目标对象上保留 setter。它执行的是纯粹的“属性值”浅拷贝,对访问器属性的处理机制非常特殊,也极易被忽略,理解这一点对于掌握 JavaScript 对象拷贝 的深层原理至关重要。

访问器属性会被转为普通数据属性

如果源对象的某个属性是用 get / set 定义的访问器属性,Object.assign 会读取该属性当前的返回值——即调用一次 getter 拿到结果,然后把这个值作为普通数据属性直接赋给目标对象。最终结果是:目标对象上对应的键变成了一个可读写的普通数据属性,彻底丢失了 getter/setter 行为。换句话说,Object.assign 浅拷贝 并不会保留属性描述符中的 getset 定义。

  • 源对象的 getter 不会被复制,只有它的返回值以“快照”方式写入目标对象
  • 源对象的 setter 完全丢失,目标对象上的同名属性再也无法触发任何 setter 逻辑
  • 后续你对目标对象该属性的修改,完全不会影响源对象,也不会触发任何访问器行为

无法继承或还原原始的访问器定义

这种表现背后的机制其实不复杂:Object.assign 基于 [[Get]][[Set]] 内部操作,而非 Object.getOwnPropertyDescriptor 搭配 Object.defineProperty。因此它不会保留属性的 configurableenumerablewritable 等特性,更不用说 get / set 函数本身了。如果你想实现 保留访问器属性的拷贝,必须采用更底层的方法。

  • 即使源属性是不可枚举的,只要它能被 for...inObject.keys 遍历到(即 enumerable: true),就会被拷贝
  • 若要完整保留访问器定义,必须手动使用 Object.getOwnPropertyDescriptors 配合 Object.defineProperties 来实现

实际例子说明行为差异

来看一个具体的示例,直观感受 JavaScript 访问器属性拷贝 的差异:

const src = {
  _value: 42,
  get foo() { return this._value * 2; },
  set foo(v) { this._value = v / 2; }
};

const target = {};
Object.assign(target, src);

console.log(target.foo); // 84(getter 被执行一次,结果被固化)
target.foo = 100;
console.log(target.foo); // 100(已变成普通数据属性,不再触发 setter)
console.log(src._value); // 42(未改变,setter 没生效)

看到了吗?target.foo 现在是一个纯数据属性,与 src 的访问器逻辑彻底脱钩。无论你后续如何修改它,都不会影响源对象,因为 setter 已经彻底丢失了。这个例子清楚地展示了 Object.assign 对 getter/setter 的处理 与直觉之间的差距。

需要保留访问器时的替代方案

如果你需要进行深拷贝,或者想要保留访问器以及属性描述符等元信息,那就得换一种方式,不要直接使用 Object.assign

  • 使用 Object.getOwnPropertyDescriptors(src) 获取完整的属性描述符
  • 再通过 Object.defineProperties(target, descriptors) 将它们复制到目标对象
  • 注意:这仍然是浅拷贝,如果嵌套对象或访问器内部逻辑较为复杂,还需要额外处理才能实现真正意义上的 JavaScript 深拷贝保留访问器
来源:https://www.php.cn/faq/2734462.html
上一篇SCSS函数自动计算CSS行高提升排版美感 下一篇大型低代码报表引擎函数表达式按需动态装载公式解析器
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
Vue应用中异步更新性能问题的优化策略详解
前端开发 · 2026-07-03

Vue应用中异步更新性能问题的优化策略详解

先来看一个令许多开发者感到困惑的场景:明明修改了数据,DOM 却“毫无反应”,无法获取最新的高度,也无法计算正确的坐标。这并非 Vue 的缺陷,反而是它精心设计的性能优化策略。核心在于——你需要学会与它“异步更新”的特性协作,而非硬碰硬。 所谓的“异步更新性能问题”,本质上是一种认知偏差。Vue 的

如何避免原型对象挂载大体积动态数组内存污染
前端开发 · 2026-07-03

如何避免原型对象挂载大体积动态数组内存污染

原型链上的大数组:一个隐蔽的内存冲击波 先给个核心判断:直接在原型对象上挂载一个大体积动态数组,这既不是传统意义上的内存“污染”,也不是安全漏洞那种“污染”,而是一种相当隐蔽但后果严重的内存管理失当。它会导致所有实例共享同一份数据,而且正因为生命周期跟整个原型链绑定得太紧,垃圾回收器(GC)根本看不

利用堆栈信息精准定位显式绑定错误对象致未定义异常
前端开发 · 2026-07-03

利用堆栈信息精准定位显式绑定错误对象致未定义异常

深入追踪:显式绑定传错对象引发的未定义异常 说实话,这类问题在JavaScript开发中相当常见——显式绑定传错了对象,然后方法执行时静默失败、访问undefined、或者抛出TypeError。但真正的难点不在于“报了什么错”,而在于“到底是哪个对象被绑错了”。要解决它,需要跳出堆栈的表层报错信息

ES模块中默认导出和具名导出的执行上下文
前端开发 · 2026-07-03

ES模块中默认导出和具名导出的执行上下文

export default 与具名导出在 ES Module 中的行为机制截然不同,核心差异不在于“值如何传递”,而在于绑定如何建立以及导入时如何使用。先给出总结性结论,再逐一详细拆解。 export default 是一种语法糖,而非真正的变量声明 这种设计容易引起误解。实际上,export d

详解HTML中iframe标签loading=lazy属性实现嵌入内容懒加载方法
前端开发 · 2026-07-03

详解HTML中iframe标签loading=lazy属性实现嵌入内容懒加载方法

先聊聊 loading= "lazy " 这个属性——它本意是让 iframe 实现延迟加载,但实际落地时常常“失效”。这并非程序漏洞,而是浏览器内置的防御机制:只有所有条件同时触发,它才会真正推迟资源请求。比如 src 必须是跨域地址(类似 https: widget example com emb