手写深拷贝

59 阅读2分钟

引入的赋值:指向同一个对象,相互之间会影响

对象的浅拷贝:只是浅层的拷贝,内部引入对象时,依然会相互影响

对象的深拷贝:两个对象不再有任何关系,不会相互影响

JSON实现深拷贝

const obj = JSON.parse(JSON.stringify(对象))

上面的方法可以实现深拷贝。但是:

1:当对象中存在function函数的时候,会自动忽略

2:Symbol也会被忽略

3:如果对象中存在对象的循环引用,则会报错

回调函数实现

    function isObject(value){
        const typeValue = typeof value
        return (value !== null) && (typeValue === "function" || typeValue === "object")
    }
    
    function deepClone(orginValue){
        if(!isObject(originValue)){
            return originValue
        }

        
        const newObj = {}
        for(const key in orginValue){
            newObj[key] = deepClone(orginValue[key])
        }
        return newObj
    }
    

多种类型判断

    function isObject(value) {
  const valueType = typeof value
  return (value !== null) && (valueType === "object" || valueType === "function")
}

function deepClone(originValue) {
  // 判断是否是一个Set类型
  if (originValue instanceof Set) {
    return new Set([...originValue])
  }

  // 判断是否是一个Map类型
  if (originValue instanceof Map) {
    return new Map([...originValue])
  }

  // 判断如果是Symbol的value, 那么创建一个新的Symbol
  if (typeof originValue === "symbol") {
    return Symbol(originValue.description)
  }

  // 判断如果是函数类型, 那么直接使用同一个函数
  if (typeof originValue === "function") {
    return originValue
  }

  // 判断传入的originValue是否是一个对象类型
  if (!isObject(originValue)) {
    return originValue
  }

  // 判断传入的对象是数组, 还是对象
  const newObject = Array.isArray(originValue) ? []: {}
  for (const key in originValue) {
    newObject[key] = deepClone(originValue[key])
  }

  // 对Symbol的key进行特殊的处理
  const symbolKeys = Object.getOwnPropertySymbols(originValue)
  for (const sKey of symbolKeys) {
    // const newSKey = Symbol(sKey.description)
    newObject[sKey] = deepClone(originValue[sKey])
  }
  
  return newObject
}


// 测试代码
let s1 = Symbol("aaa")
let s2 = Symbol("bbb")

const obj = {
  name: "why",
  age: 18,
  friend: {
    name: "james",
    address: {
      city: "广州"
    }
  },
  // 数组类型
  hobbies: ["abc", "cba", "nba"],
  // 函数类型
  foo: function(m, n) {
    console.log("foo function")
    console.log("100代码逻辑")
    return 123
  },
  // Symbol作为key和value
  [s1]: "abc",
  s2: s2,
  // Set/Map
  set: new Set(["aaa", "bbb", "ccc"]),
  map: new Map([["aaa", "abc"], ["bbb", "cba"]])
}

const newObj = deepClone(obj)
console.log(newObj === obj)

obj.friend.name = "kobe"
obj.friend.address.city = "成都"
console.log(newObj)
console.log(newObj.s2 === obj.s2)

循环引用添加


function isObject(value){
    const valueType = typeof value
    return (value !== null) && (valueType === "object" || valueType === "function")
}


function deepClone(originValue,map = new WeakMap()){
    //判断是否是一个Set类型
    if(originValue instanceof Set){
        return new Set([...originValue])
    }

    if(originValue instanceof Map){
        return new Map([...originValue])
    }

    //判断当前传入的对象是否是Symbol类型
    if(typeof originValue === "symbol"){
        return Symbol(originValue.description)
    }


    //判断传入的originValue是否是一个对象类型
    if(typeof originValue === "function"){
        return originValue
    }


    //判断传入的originValue是否是一个对象类型
    if(!isObject(originValue)){
        return originValue
    }   
    
    if(map.has(originValue)){
        return map.get(originValue)
    }

    //判断传入的对象是数组还是对象
    const newObject = Array.isArray(originValue) ? [] : {}
    map.set(originValue,newObject)
    for(const key in originValue){
        newObject[key] = deepClone(originValue[key],map)
    }

    //对Symbol的key进行特殊的处理
    const symbolKeys = Object.getOwnPropertySymbols(originValue)
    for(const sKey of symbolKeys){
        newObject[sKey] = deepClone(originValue[sKey],map)
    }

    return newObject
}

let s1 = Symbol("aaa")
let s2 = Symbol("bbb")
const obj = {
    name:"aa",
    friend:{
        name:"bb",
        parent:{
            name:"cc",
        }
    },
    hobby:["ABC","AAA","CCC"],
    foo:function(){
        console.log("1111")
    },
    [s1]:"abc",
    s2:s2,
    set: new Set(["aaa","bbb","ccc"]),
    map: new Map([["111","222"],["333"]]),
    
}
obj.info = obj

const Nobj = deepClone(obj)

console.log(Nobj)

console.log(Nobj === obj)