JavaScript 数组浅拷贝陷阱与对象深拷贝正确实践

9次阅读

JavaScript 数组浅拷贝陷阱与对象深拷贝正确实践

使用扩展运算符 `[…arr]` 仅创建数组的浅拷贝,无法隔离嵌套对象的修改;要真正避免原数组被影响,必须对内部对象也进行拷贝(即深拷贝或结构化克隆)。

javaScript 中,数组拷贝常被误认为“复制了全部内容”,但事实是:[…users] 仅执行浅拷贝(shallow copy——它新建了一个数组容器,但其中每个元素(尤其是对象)仍指向内存中同一引用。因此,当你通过 list.map() 修改 x.userName 时,实际是在修改原始对象的属性,users 数组中的对应对象自然同步变更。

✅ 正确做法:确保对象层级也被复制

方案一:使用 map() + 展开语法(推荐,轻量且语义清晰)

const users = [   { userUID: '123', userName: 'TOTO' },   { userUID: '345', userName: 'TITI' },   { userUID: '678', userName: 'TATA' } ];  // 创建新数组,并为每个对象生成独立副本 const list = users.map(obj => ({ ...obj }));  // 安全修改:只影响副本,不影响 users const listModified = list.map(x =>   x.userUID === '678' ? { ...x, userName: '' } : x );  console.log(users);        // [{userUID:'123',userName:'TOTO'}, ..., {userUID:'678',userName:'TATA'}] ← 未改变 console.log(listModified); // [..., {userUID:'678',userName:''}] ← 仅副本被更新

✅ 优点:无副作用、不依赖 jsON 序列化、支持函数/undefined/date 等(ES2023+ structuredClone() 更佳)、类型友好(typescript 友好)。

方案二:使用 structuredClone()(现代标准,最健壮)

const list = structuredClone(users); const listModified = list.map(x =>   x.userUID === '678' ? { ...x, userName: '' } : x );

⚠️ 注意:目前主流浏览器已支持(chrome 98+, firefox 94+, safari 16.4+),node.js 17.0+ 启用 –harmony-structured-cloning 或 18.12+ 原生支持。它是 ecmascript 标准定义的真正深拷贝方法,能安全处理 Map、Set、Date、regexpArrayBuffer 等复杂类型。

❌ 避免方案:json.parse(JSON.stringify())

const list = JSON.parse(JSON.stringify(users)); // 不推荐

该方式虽能实现深拷贝,但存在严重限制:会丢失 undefined、函数、symbol、Date 对象(转为空对象)、正则表达式循环引用,且 Date 会被转为字符串。仅适用于纯 JSON 兼容的简单数据结构

? 关键总结

  • […arr]、arr.slice()、Array.from(arr) 都只做浅拷贝,不适用于含对象的数组;
  • 修改对象属性前,务必先创建该对象的副本(如 {…obj});
  • 单次映射修改可一步完成:users.map(x => x.userUID === ‘678’ ? {…x, userName: ”} : {…x});
  • 若需完整深拷贝且环境支持,优先选用 structuredClone();否则用 map + 展开语法组合,兼顾兼容性与安全性。

text=ZqhQzanResources