深拷贝 和 浅拷贝
1. 首先需要了解一下在内存中数据的存放形式。内存中,分为了 栈区、堆区、全局/静态区、只读区。栈区主要存放局部变量值、函数命名参数,堆区存放引用类型变量。全局/静态区存放全局变量和静态变量,只读区存放常量和代码段。
2. 深拷贝和浅拷贝实际上是针对于应用类型数据来说的,因为对于基本数据类型变量来说,应该都归于深拷贝。
浅拷贝:创建一个新对象,这个新对象有原始对象属性值的一份拷贝,如果是基本数据类型,那么拷贝的是基本数据类型的值,如果是引用数据类型,那么拷贝的是它的地址,新数据和原数据会互相影响。
深拷贝:将一个对象完整的拷贝一份,存到堆区,新对象和原对象不会互相影响。
这里 Copy 别人的图片,链接:https://juejin.cn/post/6844904197595332622


当我们创建一个对象 obj,这个对象的地址被保存在栈区,而地址所指向的内容就是对象的内容,保存在堆区。当我们把这个对象直接利用赋值运算符复制一份给 obj_ 时,obj_ 存放的地址实际上和 obj 的值相同,都指向堆区中同一份空间。这就意味着这是一个浅拷贝,obj 和 obj_ 的内容改变会互相影响。
let obj = {
name: 'James'
};
let obj_ = obj;
obj.name = 'new Name';
console.log(obj_);
![]()
3. 如何实现深拷贝、浅拷贝?
【1】实现浅拷贝的方式:
(1)Object.assign(dest, src1, src2......) 方法,它的作用是:将 src1、src2...... 上的属性均拷贝一份,添加到 dest 对象上,如果有重复属性,默认以后一个出现的属性值作为最终值,方法返回 dest 对象。
let dest = {};
let src = {
obj: {
name: 'James'
}
};
let d = Object.assign(dest, src);
console.log(d); // { obj: { name: 'James' } }
src.obj.name = 'new Name';
console.log(d); // { obj: { name: 'new Name' } }
(2)Array.prototype.slice( [ begin [, end] ] ) 方法,作用是将原数组从 begin 处开始【包含 begin 处的值】,到 end 处结束【不包含 end 处的值】的所有数组值拷贝一份,返回新的数组。
let src = [
{
name: 'James'
}, 2, 3, 4
];
let dest = src.slice(); // 不写 begin、end 默认将全部值拷贝
console.log(dest); // [ { name: 'James' }, 2, 3, 4 ]
src[0].name = 'new Name';
console.log(dest); // [ { name: 'new Name' }, 2, 3, 4 ]
(3)Array.prototype.concat 方法:
let src = [
{
name: 'James'
}, 5, 6, 7
];
let dest = [].concat(src);
console.log(dest); // [ { name: 'James' }, 5, 6, 7 ]
src[0].name = 'new Name';
console.log(dest); // [ { name: 'new Name' }, 5, 6, 7 ]
(4)对象展开运算符:【此处是 Copy 上面提到链接的代码】
let obj1 = { name: 'Kobe', address:{x:100,y:100}}
let obj2= {... obj1}
obj1.address.x = 200;
obj1.name = 'wade'
console.log('obj2',obj2) // obj2 { name: 'Kobe', address: { x: 200, y: 100 } }
(5)函数库 lodash 的 clone 方法
【2】实现深拷贝的方式:
(1)JSON.stringify 结合 JSON.parse 使用:但是这种方式有很大缺点,它在函数处理时无能为力,函数会被转化为null,且存在循环引用时,会出错。
let src = [
{
name: 'James'
}, 8
];
let dest = JSON.parse(JSON.stringify(src));
console.log(dest); // [ { name: 'James' }, 8 ]
src[0].name = 'new Name';
console.log(dest); // [ { name: 'James' }, 8 ]
(2)函数库 lodash 的 cloneDeep 方法
(3)自己实现一个深拷贝:
function DeepClone(target) {
if (typeof target === 'object') {
const dest = Array.isArray(target) ? [] : {};
for (const key in target) {
dest[key] = DeepClone(target[key]);
}
return dest;
} else {
return target;
}
}

浙公网安备 33010602011771号