YBFACC / blog

仅记录个人学习使用
3 stars 0 forks source link

深拷贝 #32

Open YBFACC opened 4 years ago

YBFACC commented 4 years ago

深拷贝

深拷贝的原因

对引用类型(Object)进行拷贝时,不会重新开辟新的地址而是直接复制地址。

例子

let obj = {
  a: 'a',
  b: 'b',
  c: {
    c1: 'c1',
    c2: 'c2'
  }
}

function copy(object) {
  let _obj = {}
  for (const key of Object.keys(obj)) {
    _obj[key] = object[key]
  }
  return _obj
}

let temp = copy(obj)

temp.c.c1 = 'test'

console.log(obj.c.c1)//test
console.log(temp.c.c1)//test

我们拷贝的对象中的属性改变,原对象中的属性也会改变。

实现深拷贝

JSON.parse(JSON.stringify())

此方法可以实现深拷贝,但是有缺点:

function A() {
  this.a = 'A'
}
A.prototype.YBF = function (params) {}

let a = new A()
let aa = JSON.parse(JSON.stringify(a))
let obj1 = { name: 'obj1' }
let obj2 = { name: 'obj2' }
obj1.a = obj2
obj2.a = obj1

let obj3 = {
  b: obj1
}
JSON.parse(JSON.stringify(obj3))
let list = [1, 1, 1, 1]
let set = new Set(list)
let rex = new RegExp('adb')
let map = new Map([{ 1: 1 }, { 2: 2 }])

let a = {
  list: list,
  set: set,
  rex: rex,
  map: map
}
let aa = JSON.parse(JSON.stringify(a))

试了下就数组可以

代码实现

const isType = (obj, type) => {
  if (typeof obj !== 'object') return false
  const typeString = Object.prototype.toString.call(obj)
  let flag
  switch (type) {
    case 'Array':
      flag = typeString === '[object Array]'
      break
    case 'Set':
      flag = typeString === '[object Set]'
      break
    case 'Map':
      flag = typeString === '[object Map]'
      break
    default:
      flag = false
  }
  return flag
}

const deepClone = parent => {
  const hasClone = new Set()
  const _deepClone = parent => {
    if (parent === null) return null
    if (hasClone.has(parent)) {
      return parent
    }
    if (typeof parent !== 'object') return parent
    let child
    hasClone.add(parent)
    if (isType(parent, 'Array')) {
      child = []
      for (const iterator of parent) {
        child.push(_deepClone(iterator))
      }
    } else if (isType(parent, 'Map')) {
      child = new Map()
      for (const [key, value] of parent) {
        child.set(key, _deepClone(value))
      }
    } else if (isType(parent, 'Set')) {
      child = new Set()
      for (const iterator of parent) {
        child.add(_deepClone(iterator))
      }
    } else {
      proto = Object.getPrototypeOf(parent)
      child = Object.create(proto)
      for (const key in parent) {
        child[key] = _deepClone(parent[key])
      }
    }
    return child
  }
  return _deepClone(parent)
}

参考

面试官:请你实现一个深克隆

JS深拷贝总结