js笔记-实现深拷贝函数

96 阅读3分钟

什么是深拷贝函数::简单点来说,就是假设B复制了对象A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,如果B没变,那就是深拷贝

深拷贝方案01-简单的深拷贝函数,这种深拷贝函数的弊端是不能对对象里的函数和symbol进行处理。
const obj = {
  name: 'lhm',
  friend: {
    name: 'kobe'
  }
}

const info  = JSON.parse(JSON.stringify(obj))
console.log(info === obj);  // false
深拷贝方案02-实现深拷贝方法v1-基本实现
// 工具函数,判断是否是一个对象
function isObject(value) {
  // 查看类型
  const valueType = typeof value
  const isObj = (value != null) && (valueType === "object" || valueType === "function")
  return isObj
}

function deepClone(originValue) {
  // 判断传入的originValue是否是一个对象类型
  if(!isObject(originValue)) {
    return originValue
  }
  const newObject = {}
  for(const key in originValue) {
    newObject[key] = deepClone(originValue[key])
  }
  return newObject
}

const obj = {
  name: 'lhm',
  age: 18,
  friend: {
    name: "james"
  }
}

const newObj = deepClone(obj)
obj.friend.name = 'kobe'
console.log(newObj);
深拷贝方案03-实现深拷贝方法v2-其他的类型
// 工具函数,判断是否是一个对象
function isObject(value) {
  // 查看类型
  const valueType = typeof value
  const isObj = (value != null) && (valueType === "object" || valueType === "function")
  return isObj
}

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) {
    newObject[skey] = deepClone(originValue[skey])
  }
  return newObject
}

let s1 = Symbol("aaa")
let s2 = Symbol("bbb")

const obj = {
  name: 'lhm',
  age: 18,
  friend: {
    name: "james"
  },
  hobbies: ["abc", 'cba', "nba"],
  foo: function () {
    console.log('foo function');
  },
  [s1]: "abc",
  s2: s2,
  set: new Set(["aaa", "bbb"]),
  map: new Map([["aaa", "bbb"], ["abc", "cba"]])

}

const newObj = deepClone(obj)
obj.friend.name = 'kobe'
console.log(newObj);
深拷贝方案04-实现深拷贝方法v3-循环引用
// 工具函数,判断是否是一个对象
function isObject(value) {
  // 查看类型
  const valueType = typeof value
  const isObj = (value != null) && (valueType === "object" || valueType === "function")
  return isObj
}
function deepClone(originValue, map = new WeakMap()) {
  // 判断是否是一个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
  }
  // 如果map中有originValue,就返回originValue中的值
  if(map.has(originValue)) {
    return map.get(originValue)
  }
  // 判断传入的对象是数组,还是对象
  const newObject = Array.isArray(originValue) ? [] : {}
  // 把originValue: newObject存到map中
  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: 'lhm',
  age: 18,
  friend: {
    name: "james"
  },
  hobbies: ["abc", 'cba', "nba"],
  foo: function () {
    console.log('foo function');
  },
  [s1]: "abc",
  s2: s2,
  set: new Set(["aaa", "bbb"]),
  map: new Map([["aaa", "bbb"], ["abc", "cba"]]),
}
obj.info = obj

const newObj = deepClone(obj)
obj.friend.name = 'kobe'
console.log(newObj);