如何自我实现深拷贝

58 阅读1分钟

在 JavaScript 中栈存放的就是值类型的数据和引用类型的地址,而引用类型真正的数据被存放在堆中。

let obj={
  name:'ut',
  size:{width:70,heigh:180},
  a: undefined,
  fun: function rap() { }, 
  advantage:['money'],
  reg: /\d+/
}

image.png

对于引用(对象)类型来说,这种只是复制对象引用地址被称为浅拷贝(shallow copy),与之对应的,如果在堆中拷贝了一模一样的数据则被称为深拷贝(deep copy)。

方案一:Object.assign

Object.assign(obj);

缺陷:如果是多层的话 就是浅拷贝 一层就是深拷贝

方案2: JSON.parse(JSON.stringify(obj)

JSON.parse(JSON.stringify(obj);

缺陷:方法不能拷贝

方案3:解构赋值

缺陷:针对一维数组深拷贝,多维数组是浅拷贝

方案4:手写

function deepClone(value,hash = new WeakMap){ // 弱引用,不要用map
    // null 和 undefiend 是不需要拷贝的
    if(value == null){ return value;}
    if(value instanceof RegExp){return new RegExp(value)}
    if(value instanceof Date){return new Date(value)}
    // 函数是不需要拷贝
    if(typeof value != 'object') return value;
    let obj = new value.constructor(); // [] {}
    // 说明是一个对象类型
    if(hash.get(value)){
        return hash.get(value)
    }
    hash.set(value,obj);
    for(let key in value){ // in 会遍历当前对象上的属性 和 __proto__指代的属性
        // 补考呗 对象的__proto__上的属性
        if(value.hasOwnProperty(key)){
            // 如果值还有可能是对象 就继续拷贝
            obj[key] = deepClone(value[key],hash);
        }
    }
    return obj
    // 区分对象和数组 Object.prototype.toString.call
}


let o = {};
o.x = o;
let o1 = deepClone(o); // 如果这个对象拷贝过了 就返回那个拷贝的结果就可以了
console.log(o1);

方案5 lodash.cloneDeep()实现深拷贝

方案6 jQuery的extend方法实现深拷贝