浅拷贝
方法一:Object.assign()
Object.assign(target, ...sources)
- 不能拷贝继承属性
- 不能拷贝不可枚举属性
- 能拷贝Symbol 类型的属性
方法二:扩展运算符
let cloneObj = { ...obj };
缺陷和 Object.assign() 一样
方法三:concat 拷贝数组
let arr = [1, 2, 3];
let newArr = arr.concat();
newArr[1] = 100;
console.log(arr); // [ 1, 2, 3 ]
console.log(newArr); // [ 1, 100, 3 ]
方法四:slice 拷贝数组
let arr = [1, 2, {val: 4}];
let newArr = arr.slice();
newArr[2].val = 1000;
console.log(arr);
手动实现一个浅拷贝
const shallowClone = (target) => {
if (typeof target === 'object' && target !== null) {
const newTarget = Array.isArray(target) ? [] : {};
for (let pro in target) {
if (target.hasOwnProperty(pro)) {
newTarget[pro] = target[pro];
}
}
return newTarget;
}
return target;
}
深拷贝
方法一:JSON.stringify
let obj1 = { a:1, b:[1,2,3] }
let str = JSON.stringify(obj1);
let obj2 = JSON.parse(str);
console.log(obj2);
- 拷贝的对象如果有函数、undefined、symbol ,会被清除,键值对消失
- 拷贝的 Date 引用类型,会变成字符串
- 拷贝的 RegExp 引用类型,会变成空对象
- 拷贝的对象含有 NaN、Infinity、-Infinity 会变成null
- 不能拷贝不可枚举属性
- 不能拷贝对象的原型链
- 不能拷贝对象的循环引用
手动实现一个深拷贝
const isComplexDataType = obj => (
typeof obj === 'object'
) && (obj !== null)
const deepClone = function (obj, hash = new WeakMap()) {
// 日期对象直接返回一个新的日期对象
if (obj.constructor === Date) {
return new Date(obj);
}
// 正则对象直接返回一个新的正则对象
if (obj.constructor === RegExp) {
return new RegExp(obj);
}
// 如果循环引用了就用 weakMap 来解决
if (hash.has(obj)) {
return hash.get(obj);
}
// 利用Object 的 getOwnPropertyDescriptors 方法可以获得对象的所有属性,以及对应的特性,
// 结合 Object 的 create 方法创建一个新对象,并继承传入原对象的原型链;
let allDesc = Object.getOwnPropertyDescriptors(obj)
let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc)
hash.set(obj, cloneObj)
for (let key of Reflect.ownKeys(obj)) {
// 针对能够遍历对象的不可枚举属性以及 Symbol 类型,我们可以使用 Reflect.ownKeys 方法;
cloneObj[key] = (isComplexDataType(obj[key]) && typeof obj[key] !== 'function')
? deepClone(obj[key], hash)
: obj[key];
}
return cloneObj
}