最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
JavaScript 中 Object.assign 在拷贝过程中对访问器属性的处理
时间:2026-06-30 11:13:51 编辑:袖梨 来源:一聚教程网
Object.assign对访问器属性只执行值的浅拷贝,不保留getter/setter;源访问器被转为目标对象的数据属性,其返回值被固化,setter逻辑完全丢失。
Object.assign 在拷贝过程中不会调用源对象上的 getter,也不会在目标对象上保留 setter;它只执行“属性值”的浅拷贝,对访问器属性(accessor properties)的处理是特殊且容易被忽略的。
访问器属性会被转为数据属性
如果源对象某个属性是通过 get / set 定义的访问器属性,Object.assign 会读取该属性当前的 返回值(即调用 getter),然后把这个值作为普通数据属性赋给目标对象——目标对象上对应键将变成一个可读写的 数据属性,不再具备 getter/setter 行为。
- 源对象的 getter 不会被复制,仅其返回值被“快照”式地写入目标对象
- 源对象的 setter 完全丢失,目标对象上同名属性无法触发任何 setter 逻辑
- 后续对目标对象该属性的修改不会影响源对象,也不触发任何访问器逻辑
无法继承或还原访问器定义
Object.assign 的行为基于 [[Get]] 和 [[Set]] 内部操作,而非 Object.getOwnPropertyDescriptor + Object.defineProperty。因此它不保留属性的 configurable、enumerable、writable 等特性,更不会保留 get / set 函数本身。
- 即使源属性是不可枚举的,只要它能被
for...in或Object.keys遍历到(即 enumerable: true),就会被拷贝 - 若想完整保留访问器定义,必须手动使用
Object.getOwnPropertyDescriptors配合Object.defineProperties
实际例子说明行为差异
例如:
立即学习“Java免费学习笔记(深入)”;
const src = { _value: 42, get foo() { return this._value * 2; }, set foo(v) { this._value = v / 2; }};<p>const target = {};Object.assign(target, src);</p><p>console.log(target.foo); // 84(getter 被执行一次,结果被固化)target.foo = 100;console.log(target.foo); // 100(已变成普通数据属性,不再触发 setter)console.log(src._value); // 42(未改变,setter 没生效)
此时 target.foo 是一个纯数据属性,和 src 的访问器逻辑完全脱钩。
需要保留访问器时的替代方案
若需深拷贝或保留访问器、属性描述符等元信息,应避免直接使用 Object.assign:
- 用
Object.getOwnPropertyDescriptors(src)获取完整属性描述符 - 再用
Object.defineProperties(target, descriptors)复制过去 - 注意:这仍只是浅拷贝,嵌套对象/访问器内部逻辑仍需另行处理