深拷贝

66 阅读1分钟

一、浅拷贝

// 1、数组浅拷贝
// let newArr = [...arr];
// newArr = arr.concat([]);
// newArr = arr.slice();

// 2、对象的浅拷贝

let obj = {
0: 'math',
1: 'chinese',
2: 'elglish',
score: {
    math: 98,
    chinese: 100,
    elglish: 19,
},
reg: /\d+/img,
time: new Date,
friends: ['tom', 'jerry'],
say: function () {
    console.log('good good study!');
},
tag: Symbol('TAG'),
[Symbol.toStringTag]: 'object'
};

/* 
(1)
let newObj = {
    ...obj
};
(2)
newObj = Object.assign({}, obj); 
// 处理的时候包含了原始对象中 Symbol属性 的处理
*/
(3) 自己用for in遍历的时候不支持对Symbol属性的处理
let newObj = {}
for (var k in obj) {
    newObj[k] = obj[k]
}
第二个输出的结果并没有输出Symbol(Symbol.toStringTag)类型的属性

(4) Object.getOwnPropertySymbols(obj)专门能够获得所有的Symbol类型的属性
    var keys = [
    ...Object.keys(obj),
    ...Object.getOwnPropertySymbols(obj)
]
let newObj = {}
keys.forEach((item, index) => {
    newObj[item] = obj[item]
})
console.log(newObj)

二、封装浅拷贝

// 浅克隆

function shallowClone(obj) {
  let type = _.toType(obj),
      Ctor = obj.constructor;

// 对于Symbol/BigInt
if (/^(symbol|bigint)$/i.test(type)) return Object(obj);

// 对于正则/日期的处理
if (/^(regexp|date)$/i.test(type)) return new Ctor(obj);

// 对于错误对象的处理 (只有获取message才能是和之前相同)
if (/^error$/i.test(type)) return new Ctor(obj.message);

// 对于函数
if (/^function$/i.test(type)) {
    // 返回新函数:新函数执行还是把原始函数执行,实现和原始函数相同的效果
    return function () {
        return obj.call(this, ...arguments);
    };
}

// 数组或者对象
if (/^(object|array)$/i.test(type)) {
    let keys = [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)],
        result = new Ctor();
    _.each(keys, key => {
        result[key] = obj[key];
    });
    return result;
}

return obj;

}

三、深拷贝

// 深克隆:只要有下一级的,我们就克隆一下(浅克隆)
function deepClone(obj, cache = new Set()) {
    let type = _.toType(obj),
        Ctor = obj.constructor;
    if (!/^(object|array)$/i.test(type)) return shallowClone(obj);

    // 避免无限套娃
    if (cache.has(obj)) return obj;
    cache.add(obj);

    let keys = [
            ...Object.keys(obj),
            ...Object.getOwnPropertySymbols(obj)
        ],
        result = new Ctor();
    _.each(keys, key => {
        // 再次调用deepClone的时候把catch传递进去,保证每一次递归都是一个cache
        result[key] = deepClone(obj[key], cache);
    });
    return result;
}