使用展开运算符复制对象数组后执行splice,为何原数组未被修改?
核心概念澄清
你对浅拷贝的作用边界存在认知偏差,当前场景下展开运算符实现的浅拷贝完全符合预期,不需要对嵌套对象做深克隆。
展开运算符对数组的浅拷贝实际做了什么
用[...array]生成数组副本的本质是:
- 在内存中创建一个完全独立的新数组容器(和原数组的内存地址不存在重叠)
- 将原数组中存储的所有元素的引用,原封不动复制到新数组的对应槽位中
也就是说,新数组和原数组是两个完全独立的容器,但因为没有对嵌套的引用类型(比如这里的普通对象)创建额外副本,两个数组里存储的对象引用是完全一致的——这就是“浅”的核心含义:只拷贝第一层的容器结构,不拷贝容器内引用指向的具体内容。
为什么splice操作不会改动原数组
你对cloneArray执行的splice(1,1,newObject),本质是修改cloneArray这个新容器自身的结构:把新数组第二个槽位里存储的引用,从原本指向{ name: 'Object 2', body: '456' }的地址,替换成指向你新建的newObject的地址。
整个操作过程既没有触碰原数组的容器结构,也没有修改两个数组共同指向的嵌套对象的内部属性,原数组的容器结构没有任何改动,自然保持原样没有变化。
浅拷贝的联动边界
只有当你顺着新数组的元素引用,直接修改嵌套对象的内部属性时,才会出现原数组同步变化的情况,示例代码如下:
// 顺着cloneArray的引用修改共同指向的对象属性 cloneArray[1].body = 'modified value'
这种场景下,cloneArray[1]和原数组array[1]指向的是堆内存中同一个对象,对这个对象的属性做修改,原数组对应的引用自然能读到改动后的值——这也是需要引入深拷贝的典型场景:当你既要操作数组结构,又要修改嵌套对象的内部属性、且不希望原数组受影响时,才需要对所有嵌套对象做全量克隆。
反过来,只要你的操作是修改数组第一层的容器结构(增删数组元素、替换槽位存储的元素为新对象),无论嵌套对象的层级有多深,浅拷贝都完全可以满足需求,不需要做多余的深克隆。
内容的提问来源于stack exchange,提问作者Vladut
相关产品推荐
相关产品推荐

