大家好,我是大华!
Javascript的深拷贝和浅拷贝是啥。这俩到底有啥区别,什么时候该用哪个。
一、浅拷贝例子
假设你有个用户信息对象:
let user = {
name: '小明',
age: 25,
tags: ['前端', '篮球', '音乐']
};
现在你想复制一份,准备做点修改,但不想影响原数据。你可能会这么写:
let userCopy = Object.assign({}, user);
// 或者用扩展符
// let userCopy = { ...user };
这时候看起来一切正常:
userCopy.name = '小红';
console.log(user.name); // 小明(没变)
console.log(userCopy.name); // 小红(变了)
但问题来了,如果你改的是tags:
userCopy.tags.push('旅行');
console.log(user.tags); // ['前端', '篮球', '音乐', '旅行']
console.log(userCopy.tags); // ['前端', '篮球', '音乐', '旅行']
咦?原对象的 tags 也被改了!
这就是浅拷贝的坑——它只复制了第一层。像name、age这种基本类型没问题,但tags是个数组(引用类型),它复制的只是一个指针,两个对象其实还共用同一个数组。
二、深拷贝能解决这个问题
深拷贝复制的不只是第一层,里面的每一层都完完整整地复制一份,彻底断开联系。
怎么实现?最简单粗暴的方法:
let userDeepCopy = JSON.parse(JSON.stringify(user));
再试试:
userDeepCopy.tags.push('电影');
console.log(user.tags); // ['前端', '篮球', '音乐', '旅行'] (没变)
console.log(userDeepCopy.tags); // ['前端', '篮球', '音乐', '旅行', '电影']
这次终于互不影响了。
三、什么时候用哪个?
场景1:只是改个名字、状态,用浅拷贝就够了
比如你从接口拿到一个列表,想临时标记某个条目为“已选中”:
let list = getData(); // 假设这是接口返回的数据
let newList = list.map(item => ({
...item,
selected: false
}));
// 后来用户点了某一项
newList[0].selected = true;
这种只改第一层属性的,完全可以用浅拷贝,简单又高效。
💡小提示:这种只读不改原数据的操作,浅拷贝足够安全。
场景2:要改嵌套结构,就得上深拷贝
我在做一个表单编辑器时遇到过这个问题。数据结构长这样:
let form = {
title: '用户调查',
fields: [
{ label: '姓名', type: 'text' },
{ label: '爱好', type: 'checkbox' }
]
};
用户想复制一个类似的表单来进行修改。如果用浅拷贝:
let newForm = { ...form };
newForm.fields.push({ label: '年龄', type: 'number' });
结果发现,原来的form里也多了一个字段!因为fields数组还是同一个。
后来改用深拷贝:
let newForm = JSON.parse(JSON.stringify(form));
// 再改就安全了
场景3:注意!深拷贝也有局限
别以为深拷贝是万能的。我后来发现,如果对象里有函数、undefined、Symbol,或者有循环引用,JSON.parse(JSON.stringify()) 就会出问题。
比如:
let obj = {
name: 'test',
fn: function() { console.log('hello'); }
};
let copy = JSON.parse(JSON.stringify(obj));
copy.fn(); // 报错!fn 变成 undefined 了
这时候就得用更高级的方案,比如 Lodash 的 cloneDeep:
const _ = require('lodash');
let safeCopy = _.cloneDeep(obj);
四、一句话总结
- 浅拷贝:只复制表面一层,速度快,适合只读或只改第一层的场景。
- 深拷贝:里里外外全复制,安全但慢一点,适合要修改嵌套结构的情况。
我现在的习惯是:
- 大部分时候先用扩展符
{...obj},简单直接。 - 如果发现改着改着原数据也被动了,马上换成
JSON.stringify或_.cloneDeep。
希望这篇没那么多术语的分享,也能帮你少踩点坑。