
使用扩展运算符 `[...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、RegExp、ArrayBuffer 等复杂类型。
❌ 避免方案: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 + 展开语法组合,兼顾兼容性与安全性。










