1、释义
- 浅拷贝:创建一个新对象,这个对象有着原始对象属性值的精确拷贝;如果是基础类型拷贝的就是基础类型的值,如果是引用类型拷贝的就是内存地址;如果其中一个对象改变了这个地址就会影响另一个对象
- 深拷贝:将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新的对象,改变对象不会影响原对象
2、示例
浅拷贝
- 基本类型
基本数据类型是存储在栈内存中
var a = 1
var b = a
b = 2
console.log(a,b)
// 1 2
改变不会使原始数据改变
- 引用类型
var per = {
name:'1'
}
var per1 = per
per1.name = "2"
console.log(per,per1)
// {name: "2"} {name: "2"}
此时per1赋值的是per的地址
,per1的操作指向的是同一地址的对象per,改变会使原始数据per改变
深拷贝
var per = {
name:'1'
}
// 创建新对象
var per1 = {}
per1 = per
per1.name = '2'
console.log(per,per1)
// {name: "1"} {name: "2"}
创建per1并赋值,将per的属性值单独进行赋值,此时per1指向的是新地址,改变属性值并不影响原数据
多级结构
我们先看下单级结构
let a = [1, 2, 3];
let b = [];
a.forEach(item => {
b.push(item)
})
b[0] = 0
console.log(a, b)
// [1, 2, 3] [0, 2, 3]
这时一级拷贝是深拷贝
再改下代码变成多级结构
let a = [1, 2, 3, [4, 5]];
let b = [];
a.forEach(item => {
b.push(item)
})
b[3][1] = 4
console.log(a, b)
// [1, 2, 3, [4, 4]] [1, 2, 3, [4, 4]]
修改二维数组的元素还是会影响原数组,这时一级拷贝是浅拷贝
3、拷贝方案
首先来看看有哪些系统方法可以实现拷贝功能:
- slice()
单级结构时深拷贝,多级结构浅拷贝 - concat()
单级结构时深拷贝,多级结构浅拷贝 - Object.assign()
单级结构时深拷贝,多级结构浅拷贝 - JSON.stringify()、JSON.parse()
单级多级均为深拷贝,但需要注意无法拷贝RegExp对象、function和symbol
- deepClone递归:
function deepClone(obj: any) {
function isObject(o: any) {
return (typeof o === 'object' || typeof o === 'function') && o !== null;
}
if (!isObject(obj)) {
throw new Error('非对象');
}
let isArray = Array.isArray(obj);
let newObj = isArray ? [...obj] : { ...obj };
Reflect.ownKeys(newObj).forEach(key => {
newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key];
});
return newObj;
}
4、结论
类型 | 基础数据类型 | 引用数据类型 |
浅拷贝 | 改变不会使原始数据改变 | 改变会使原始数据改变 |
深拷贝 | 改变不会使原始数据改变 | 改变不会使原始数据改变 |
如有疑问或不足之处,欢迎交流指正