使用扩展运算符修改数组引用后仍受原对象影响的技术问题
问题分析与解决方案
我遇过不少类似的情况,核心问题其实出在浅拷贝和深拷贝的区别上——你的扩展运算符用的是浅拷贝,而实际代码里的数组元素大概率是引用类型(比如对象、嵌套数组),这就导致拷贝后的数组和原数组共享内部元素的引用,原数组修改内部元素时,拷贝数组也会跟着变。
为什么你的最小示例没问题?
你提供的示例里,数组元素是number这种基本类型,扩展运算符的浅拷贝完全够用:基本类型的值是直接复制的,拷贝后的数组和原数组各自持有独立的值,修改原数组的元素(比如替换整个数组为[1,2,4])不会影响拷贝数组。
实际代码出问题的原因
如果你的实际代码里,数组元素是引用类型(比如对象),情况就不一样了:
// 举个实际代码可能的例子 initialArrayThatChanges = [{ value: 1 }, { value: 2 }, { value: 3 }]; // 扩展运算符做浅拷贝,只复制数组的外层引用 initialArrayWithNoChanges = [...this.initialArrayThatChanges]; // 当你修改原数组里某个对象的属性时 this.initialArrayThatChanges[0].value = 100; // 拷贝数组里的对应对象也会跟着变,因为它们引用的是同一个对象! console.log(this.initialArrayWithNoChanges[0].value); // 输出100
这时候扩展运算符只解决了数组本身的引用问题,但内部的对象引用还是共享的,所以看起来“旧数组仍随初始对象变化”。
为什么JSON.parse(JSON.stringify(array))能解决?
这种方式是一种简单的深拷贝实现:它把整个数组(包括内部所有嵌套的对象)转换成JSON字符串,再重新解析成新的对象/数组。这个过程会重新创建所有层级的元素,彻底断开和原数组的引用关联,所以修改原数组不会影响拷贝后的数组。
更合适的解决方案
如果你的数组结构比较简单(比如只有一层对象),可以用map结合扩展运算符做一层拷贝:
initialArrayWithNoChanges = this.initialArrayThatChanges.map(item => ({ ...item }));
如果是多层嵌套的复杂结构,推荐:
- 手动写递归拷贝函数,精确控制拷贝逻辑;
- 使用成熟的第三方工具库(比如Lodash的
_.cloneDeep方法),它能处理各种边缘情况(比如循环引用、特殊类型等)。
内容的提问来源于stack exchange,提问作者luifon
相关产品推荐
相关产品推荐

