把列表数据复制一份去编辑,结果原来的列表也跟着变了——这不是 bug,是引用赋值。JS 里对象存的是地址,const b = a 只是复制地址,两个变量指向同一块内存。想互不影响,就得做深拷贝。

先分清浅拷贝和深拷贝

展开运算符 {...obj} 和 Object.assign 都只拷第一层,里面嵌套的对象还是共享的,这叫浅拷贝。数据里嵌着数组、嵌着对象的,浅拷贝等于没解决问题。数组也一样,slice 和 concat 都是浅拷贝,里面的对象照样共享。

JSON 方法的四个硬伤

网上一搜,多数人给的是 JSON.parse(JSON.stringify(obj)),能用,但有四个坑:函数和 undefined 会直接丢;Date 对象变成字符串;正则、Map、Set 这些结构会损坏;对象里有循环引用直接报错。临时处理接口返回的纯数据勉强够用,通用场景别依赖它。

现在优先用 structuredClone

浏览器和 Node 17 以后内置了 structuredClone,Date、Map、Set、循环引用都能正确处理,一行搞定:const copy = structuredClone(obj)。限制是不能拷函数,DOM 节点也不行,碰到就抛 DataCloneError。

要兼容老环境或者必须拷函数,就上 lodash 的 cloneDeep,多年生产验证,行为最全。自己手写递归实现是面试常考题,但要处理循环引用、各种特殊对象的边界,实际项目里没必要重复造轮子。

怎么选:纯数据用 structuredClone,老浏览器兜底用 cloneDeep,只有一层的数据直接展开运算符。验证拷没拷对也简单,改一下副本里的嵌套字段,看原对象动不动,动了就是没拷干净。