# 35、浅拷贝与深拷贝
# 浅拷贝
浅拷贝只会将对象的第一层的属性进行依次复制(遇到基本类型就直接复制值,遇到引用数据类型就复制内存地址),但是并不会进行递归复制,也就是说如果属性的值是引用数据类型的,那么拷贝后对象的值指向的还是原来对象的内存地址,只是把内存地址复制过去了而已。
# Object.assign
Object.assign(target, ...sources)
:会把所有可枚举属性的值从一个或多个源对象复制到目标对象。然后返回目标对象
# 深拷贝
深拷贝则会递归的拷贝对象的属性,遇到基本类型就直接赋值,遇到引用数据类型就创建新的相同类型的对象,再递归拷贝旧对象,赋值给新的对象。直到属性值不为引用数据类型(需要使用
hasOwnProperty
来过滤掉继承自原型链上的属性)
# 使用 JSON.stringify()
JSON.stringify()
采用JSON.stringify()
把对象转化为字符串,然后再用JSON.parse()
把字符串转化为对象,就能实现深拷贝;
弊端:
- 无法拷贝
undefined
与symbol
属性 - 无法拷贝循环引用对象
- 性能较差
let a={a:1},
b={b:1},
c={c:1};
let ary=[a,b,c];
let str=JSON.stringify(ary);
let newAry=JSON.parse(str);
console.log(newAry);
console.log(newAry[0]===ary[0]);
# 采用解构赋值
let a={a:1},
b={b:1},
c={c:1};
let ary=[a,b,c];
let [{a:A},{b:B},{c:C}]=ary;
let newAry=[{a:A},{b:B},{c:C}];
console.log(newAry);
console.log(newAry[0]===ary[0]);
# 采用递归
思路
- 1、判断是否是
null
或者 不是对象- 2、判断是否为循环引用
- 3、获取对象属性时需要考虑
Symbol
类型的属性名,Reflect.ownKeys
方法可以获取所有类型的键名,包括常规键名和Symbol
键名;
function deepClone(val,map = new WeakMap()){
if(val === null || typeof val !=='object') return val;
//循环引用
if(map.has(val)) return map.get(val);
let clone = Array.isArray(val) ? [] : {};
map.set(val,clone);
// 获取对象中所有的属性名(包含Symbol值)
let keys = Reflect.ownKeys(val);
let len = keys.length;
while(len--){
clone[keys[len]] = deepClone(val[keys[len]],map);
}
return clone;
}