# 35、浅拷贝与深拷贝

# 浅拷贝

浅拷贝只会将对象的第一层的属性进行依次复制(遇到基本类型就直接复制值,遇到引用数据类型就复制内存地址),但是并不会进行递归复制,也就是说如果属性的值是引用数据类型的,那么拷贝后对象的值指向的还是原来对象的内存地址,只是把内存地址复制过去了而已。

# Object.assign

Object.assign(target, ...sources):会把所有可枚举属性的值从一个或多个源对象复制到目标对象。然后返回目标对象

# 深拷贝

深拷贝则会递归的拷贝对象的属性,遇到基本类型就直接赋值,遇到引用数据类型就创建新的相同类型的对象,再递归拷贝旧对象,赋值给新的对象。直到属性值不为引用数据类型(需要使用hasOwnProperty来过滤掉继承自原型链上的属性)

# 使用 JSON.stringify()

JSON.stringify()

采用JSON.stringify()把对象转化为字符串,然后再用JSON.parse()把字符串转化为对象,就能实现深拷贝;

弊端:

  • 无法拷贝undefinedsymbol属性
  • 无法拷贝循环引用对象
  • 性能较差
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;
}
上次更新: 5/21/2020, 6:57:32 PM