JavaScript引用类型赋值只复制内存地址而非内容,导致修改共享对象;需用浅拷贝(如展开运算符)或深拷贝(如structuredClone)隔离数据,按需选择以避免副作用。

JavaScript 中处理复杂对象的引用类型赋值,核心在于理解“赋值不等于拷贝”——变量只是持有对内存中同一对象的引用,修改一个变量会影响所有指向它的变量。要避免意外副作用,必须主动创建新对象,而不是依赖赋值操作。
为什么直接赋值会出问题
对象、数组、函数等引用类型在赋值时只复制了内存地址,不是内容本身:
例如:
let obj1 = { name: "Alice", hobbies: ["reading"] };
let obj2 = obj1; // 只是把地址给了 obj2
obj2.name = "Bob";
console.log(obj1.name); // "Bob" —— obj1 也被改了
obj2.hobbies.push("coding");
console.log(obj1.hobbies); // ["reading", "coding"] —— 深层属性同样共享
浅拷贝:适合一层结构的对象
只复制对象第一层属性,嵌套对象仍共享引用。适用于属性值都是基本类型或不需要隔离深层结构的场景:
-
展开运算符(推荐):
const newObj = { ...oldObj }; -
Object.assign():
const newObj = Object.assign({}, oldObj); -
Array.from() 或展开运算符用于数组:
const newArr = [...oldArr];
注意:如果对象含嵌套对象、日期、正则、undefined、函数等,浅拷贝无法完全隔离。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
深拷贝:彻底隔离所有层级
递归复制每一层属性,确保新对象与原对象完全独立。常用方法有:
- JSON.parse(JSON.stringify()):简单快捷,但会丢失函数、undefined、Symbol、Date、RegExp、循环引用,且不能处理 BigInt。
- structuredClone()(现代浏览器支持):原生 API,支持 Map、Set、Date、RegExp、ArrayBuffer 等,能处理大多数复杂结构,且保留类型和循环引用(部分环境已支持)。
- Lodash 的 _.cloneDeep():兼容性好,功能全面,适合需要支持老旧环境的项目。
例如使用 structuredClone:
const deepCopy = structuredClone(originalObj);
按需选择:别为简单需求过度深拷贝
并非所有场景都需要深拷贝。合理策略更高效:
- 仅读取或临时修改?用浅拷贝 + 明确的属性覆盖即可。
- 状态管理(如 React、Vuex)?优先用不可变更新模式,例如:
{ ...state, user: { ...state.user, name: "New" } }。 - 频繁深拷贝大对象?考虑是否可重构为不可变数据结构(如 Immutable.js)或用代理(Proxy)做细粒度追踪。
不复杂但容易忽略——关键在写代码前想清楚:这个对象后续会不会被多人修改?哪一层需要隔离?然后选最轻量、最稳妥的方式。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










