push(array)和push([...array])二者有何区别?

思否 问答 👍 3 含 AI 优化版

问题

push(array)和push([...array])二者有何区别?

在 SegmentFault 查看原问题 →

由大模型辅助整理,保留原意,优化结构与可读性。

问题概述

提问者想了解 res.push(path)res.push([...path]) 这两种写法在向数组中追加元素时的本质区别,尤其是在 path 后续会被修改的场景下会产生什么不同的结果。

涉及技术

JavaScript、数组、引用类型、浅拷贝/深拷贝

期望结果

希望明确两种写法在「引用关系」上的差异,以及为什么某些场景下需要断开引用。

回答

原始回答

res.push(path) 等于把 path 的引用,追加到了数组里面。所以如果path被改变了,res里面的也会改变。

res.push([...path]),这里等于把 path 的内容拿出来,重新构建了一个数组。然后追加。这里重点是切断了引用关系。相同的办法有深浅拷贝、concat、JSON.parse(JSON.stringify)

AI 优化 · 回答整理

解答思路

res.push(path) 直接把 path 这个数组的引用存入 res,之后如果 path 本身被修改,res 里存的内容也会跟着变;而 res.push([...path]) 通过展开语法先复制出一个全新数组再存入 res,从而切断了与原 path 的引用关系,后续修改 path 不会影响已经存入 res 的数据。

示例代码

let path = [1, 2, 3];
let res = [];

res.push(path);       // 存入的是 path 的引用
path.push(4);
console.log(res);     // [[1, 2, 3, 4]]  —— res 中的数据被联动修改了

let res2 = [];
res2.push([...path]); // 存入的是一份新拷贝,切断了引用
path.push(5);
console.log(res2);    // [[1, 2, 3, 4]] —— 不受后续修改影响

详细说明

JavaScript 中数组、对象属于引用类型:变量存储的是指向堆内存中数据的引用,而不是数据本身。当直接 push(path) 时,res 数组里存的元素与外部的 path 变量指向同一块内存,二者是「同步」的——只要通过任意一个引用修改了数据,另一处读取到的都是修改后的结果。

[...path](数组展开语法)会创建一个新的数组,并把 path 中每个元素逐一复制到新数组中,这个过程相当于一次浅拷贝,res2.push([...path]) 存入的是这个新数组的引用,与原 path 已经是两个独立的内存对象,互不影响。

需要注意的是,这种切断引用的方式属于浅拷贝:如果数组元素本身也是对象/数组(嵌套引用类型),拷贝后的新数组内部元素仍然与原数组共享引用。要实现更彻底的隔离,可以使用其他等价的深/浅拷贝手段,例如 concat()Array.prototype.slice(),或对于深拷贝场景使用 JSON.parse(JSON.stringify(path))

小结

push(array) 追加的是原数组的引用,后续修改会互相影响;push([...array]) 通过展开语法完成一次浅拷贝,切断了引用关系,是否需要切断引用取决于业务上是否希望共享同一份数据。

由大模型辅助整理,保留原意,补充结构与代码格式。

回答转载自 SegmentFault

评论

评论功能即将开放。你也可以通过 邮件GitHub Issue 反馈。