扩展运算符做浅拷贝必然共享嵌套引用,只隔离第一层基本类型值;修改含两个以上点号或方括号的路径会同步影响原数据,安全做法是逐层展开重建对象。

扩展运算符(...)做浅拷贝时,嵌套对象的风险不是“可能出错”,而是必然存在——它只复制第一层,深层结构永远共享引用。关键在于提前识别风险点,并在修改前判断是否触及嵌套层级。
看清哪些值会被真正隔离,哪些只是换了个指针
基础类型(字符串、数字、布尔、null、undefined、symbol)在展开后是独立副本;但对象、数组、函数、Date、RegExp 等引用类型,只是把内存地址复制过去。例如:
const user = { name: '张三', info: { age: 28 } };-
const copy = { ...user };→copy.name和user.name互不影响 -
copy.info.age = 29;→user.info.age同步变成 29
修改前先问一句:我在改第几层?
只要赋值操作的左侧路径中包含两个以上点号(.)或方括号([]),就极可能踩中浅拷贝陷阱:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
-
copy.name = '李四'✅ 安全(第一层) -
copy.info.city = '杭州'❌ 危险(第二层,info是引用) -
copy.tags[0].label = '热门'❌ 危险(第三层,tags和其内部对象都是引用)
需要改嵌套字段时,别硬改,用显式展开替代直接赋值
想安全更新某一层嵌套属性,就手动把那层也展开重建:
- 原数据:
const data = { a: 1, user: { id: 101, profile: { name: 'Alice' } } }; - 想改
profile.name,写成:const newData = { ...data, user: { ...data.user, profile: { ...data.user.profile, name: 'Bob' } } }; - 这样每一层都新建了对象,不再共享引用
当嵌套超过两层或结构不确定,直接放弃扩展运算符
三层及以上嵌套、含函数/日期/正则/循环引用、或需批量更新多个深层字段时,扩展运算符已不适用:
- 现代浏览器可用
structuredClone()(支持 Map、Set、Date、RegExp、嵌套等) - 纯 JSON 数据可用
JSON.parse(JSON.stringify(obj))(注意会丢函数、undefined、Symbol) - 生产项目推荐
lodash.cloneDeep()或自定义递归深拷贝函数
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










