浅拷贝
- Object.assign();
Object.assign方法只会拷贝原对象自身的并且可以枚举的属性到目标对象
- 不会拷贝对象的继承属性。
- 不会拷贝对象的不可枚举属性。
- 可以拷贝Symbol类型的属性。
-
...运算符
-
原生数组拷贝的方式
- concat()
- slice()
- Array.from();
#浅拷贝
copy(target) {
if (typeof target === 'object' && target !== null) {
const copy = Array.isArray(target) ? [] : {};
for (const prop in target) {
if (Object.hasOwnProperty.call(target, prop)) {
copy[prop] = target[prop];
}
}
return copy;
}
return target;
}
深拷贝
- JSON.stringify
最简单的深拷贝的方法,就是把一个对象序列化成为JSON的字符串,并将对象里面的内容转成字符串,
最后用JSON.parse()将JSON字符串生产一个新的对象。
这种方式实现深拷贝有些地方需要注意。
- 拷贝的对象的值如果由函数,undefined, symbol这几种类型,经过JSON.stringify序列化后字符串中这个键值对会消失。
- 拷贝Date类型会变成字符串。
- 无法拷贝不可枚举的属性。
- 无法拷贝对象原型链。
- 拷贝正则引用类型会编程空对象。
- 对象中含有NaN, infinity 以及 -infinity, JSON序列化后的结果变成null
- 无法拷贝对象的循环引用,即对象成环 (obj[key]=obj)
真正的深拷贝
- 解决上述的几个问题的思路
- 如果是Date, RegExp 直接创建一个新的实例并返回
- 如果是循环引用就用weakMap解决
- 原型上的方法,可以结合 Object.getOwnPropertyDescriptors 获取对象上的所有属性及特性及 Object.getPrototypeOf原型上的方法和Object.create结合使用,创建一个新对象,并继承传入原对象的原型链。
- 对象的不可枚举属性以及Symbol类型,可以使用Reflect.ownKeys方法
copy(obj, hash = new WeakMap()) {
// 日期类型返回一个新的日期类型
if (obj instanceof Date) return new Date(obj);
// 正则对象返回新的正则对象
if (obj instanceof RegExp) return new RegExp(obj);
// 循环引用使用 weakMap解决
if (hash.has(obj)) return hash.get(obj);
const desc = Object.getOwnPropertyDescriptors(obj);
// 获取原型上的方法和对象的描述信息,创建新的对象
const copyObj = Object.create(Object.getPrototypeOf(obj), desc);
hash.set(obj, copyObj);
// 循环遍历递归内容,防止还有内存共计的问题
for (const key of Reflect.ownKeys(obj)) {
const item = obj[key];
if (typeof item === 'object' && item !== null && typeof item !== 'function') {
copyObj[key] = this.copy(item);
} else {
copyObj[key] = item;
}
}
return copyObj;
}