使用Object.assign克隆对象数组的异常问题及原理问询
问题解析与解决方案
为什么修改拷贝后的数组会影响原数组?
核心原因是**Object.assign()执行的是浅拷贝**,哪怕操作的是数组也遵循这个规则:
- 在JavaScript中,数组本质是特殊的对象,数组的索引(比如
0)就是对象的数字型属性名。 - 当你执行
Object.assign([], original)时,它会把原数组的所有“属性”(即各个索引对应的元素值)复制到新数组中。但原数组的元素是对象引用,Object.assign()只会复制这个引用,不会复制引用指向的对象本身。 - 这就导致新数组
copy的第一个元素和原数组original[0]指向同一个内存地址的对象。你在copy.forEach里修改obj.value,实际是直接修改了这个共享的对象,原数组自然会同步变化。
对应MDN说明的解释
MDN提到的“仅复制属性值,如果源值是对象引用,只会复制引用值”完全适用于你的场景:
- 数组的索引属于对象属性,数组元素就是属性值;
- 当属性值是对象引用时,
Object.assign()只会复制引用,而非对象的副本,所以修改引用指向的对象会影响所有持有该引用的变量。
实现数组深拷贝的方法
如果要实现真正的深拷贝(修改拷贝后的内部对象不影响原数组),可以用以下几种方式:
方法1:JSON序列化/反序列化(简单通用)
适合大多数没有特殊类型(如函数、Symbol、循环引用)的场景:
const original = [ { value: 1 } ]; function test() { const copy = JSON.parse(JSON.stringify(original)); copy.forEach(obj => obj.value = obj.value + 1); } console.log(original[0].value); // -> 1 test(); console.log(original[0].value); // -> 1 test(); console.log(original[0].value); // -> 1
方法2:数组map结合对象浅拷贝(适合单层对象数组)
如果数组内只有一层对象,可以用map遍历每个元素,单独拷贝对象:
const copy = original.map(obj => ({...obj})); // 或者用Object.assign const copy = original.map(obj => Object.assign({}, obj));
方法3:手动递归深拷贝(适合复杂场景)
如果需要处理函数、Symbol或循环引用,可以自己实现递归深拷贝逻辑,遍历每个属性并复制值,遇到对象则递归处理。
内容的提问来源于stack exchange,提问作者Khryus
相关产品推荐
相关产品推荐

