你在写ref="/tag/137/" style="color:#3D6345;font-weight:bold;">JavaScript时,有没有遇到过这种情况:改了一个对象的值,结果另一个对象也莫名其妙变了?这很可能是因为你碰上了浅拷贝和深拷贝的问题。
什么是拷贝?
在JavaScript中,当我们把一个对象赋值给另一个变量时,并不是所有数据都会被“复制”一份。比如:
const user = { name: '小明', info: { age: 25 } };
const copyUser = user;
copyUser.name = '小红';
console.log(user.name); // 输出:小红
看,改了copyUser,user也跟着变了。因为这只是引用传递,两个变量指向的是同一个对象。
浅拷贝:只复制一层
真正的拷贝,是要生成一个新对象。浅拷贝就是只复制对象的第一层属性。如果属性是基本类型(如字符串、数字),那就直接复制值;如果是引用类型(如数组、对象),那就只复制它的引用。
常见的浅拷贝方法有:
// 使用扩展运算符
const shallow1 = { ...user };
// 使用 Object.assign
const shallow2 = Object.assign({}, user);
但问题来了,如果对象里嵌套了对象,浅拷贝就搞不定深层数据:
const user = { name: 'Tom', profile: { city: 'Beijing' } };
const copy = { ...user };
copy.profile.city = 'Shanghai';
console.log(user.profile.city); // 输出:Shanghai
看到没?profile是对象,浅拷贝只复制了它的引用,所以改copy会影响原对象。
深拷贝:彻底复制所有层级
深拷贝会递归遍历对象的所有层级,把每一个子对象都重新创建一遍,真正做到“完全独立”。
最简单的深拷贝方法是利用JSON:
const deepCopy = JSON.parse(JSON.stringify(user));
这种方法简单粗暴,适合大多数普通场景。但它有局限:不能处理函数、undefined、Symbol,还会丢失原型链。
更靠谱的深拷贝需要自己写递归函数:
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof Array) {
return obj.map(item => deepClone(item));
}
if (typeof obj === 'object') {
const clonedObj = {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clonedObj[key] = deepClone(obj[key]);
}
}
return clonedObj;
}
}
这样就能完整复制嵌套对象,互不干扰。
实际场景举例
比如你做一个购物车功能,用户点了“编辑商品”,你拿到商品对象准备修改。如果直接用原对象,用户点取消时数据已经变了。这时候就应该用深拷贝先复制一份,等确认后再更新原数据。
又比如表单重置,你保存一份初始值的深拷贝,点“重置”时直接还原,避免误操作影响原始配置。
别盲目用深拷贝
虽然深拷贝更安全,但性能开销大,尤其是对象特别复杂的时候。如果只是平级数据,用浅拷贝完全够用。
搞清楚你的数据结构,再决定用哪种方式,别一上来就深拷贝,浪费资源。