Skip to content

实现深拷贝

js
// 简单版本
const newObj = JSON.parse(JSON.stringify(oldObj))

// 面试够用版
function deepClone(obj) {
  // 如果是值类型 或 null, 则直接return
  if (typeof obj !== 'object' || obj === null) {
    return obj
  }

  // 定义结果对象
  let copy = {}

  // 如果对象是数组,则定义结果数组
  if (obj.constructor === Array) {
    copy = []
  }
  // 遍历对象的key
  for (let key in obj) {
    // 如果key是对象自有属性
    if (obj.hasOwnProperty(key)) {
      // 递归调用深拷贝方法
      copy[key] = deepClone(obj[key])
    }
  }
  return copy
}
js
// 深拷贝
function isObject(val) {
  return typeof val === 'object' && val !== null
}

function deepClone(obj, hash = new WeakMap()) {
  if (!isObject(obj)) return obj
  if (hash.has(obj)) {
    return hash.get(onj)
  }
  let target = Array.isArray(obj) ? [] : {}
  hash.set(obj, target)
  Reflect.ownKeys(obj).forEach((item) => {
    if (isObject(obj[item])) {
      target[item] = deepClone(obj[item], hash)
    } else {
      target[item] = obj[item]
    }
  })
  return target
}

var obj1 = {
  a: 1,
  b: { a: 2 },
}
var obj2 = deepClone(obj1)
console.log(obj1)
js
// 浅拷贝
// concat、slice、JSON.stringify 都算是技巧类
var shallowCopy = function (obj) {
  // 只拷贝对象
  if (typeof obj !== 'object') return
  // 判断是数组还是普通对象
  var newObj = obj instanceof Array ? [] : {}
  // 遍历obj,并且判断是obj的属性才拷贝
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = obj[key]
    }
  }
  return newObj
}

// 深拷贝
var deepCopy = function (obj) {
  if (typeof obj !== 'object') return
  var newObj = obj instanceof Array ? [] : {}
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key]
    }
  }
  return newObj
}

// Object.assign也是浅拷贝,如果是对象的化拷贝的是地址
// ...也可以实现浅拷贝

//JSON.parse(JSON.stringify(object))是深拷贝但是有局限
/**
 * 会忽略 undefined
   会忽略 symbol
   不能序列化函数
   不能解决循环引用的对象
 */

//推荐使用lodsh深拷贝
function deepClone(obj) {
  function isObject(o) {
    return (typeof o === 'object' || typeof o === 'function') && o !== null
  }

  if (!isObject(obj)) {
    throw new Error('非对象')
  }

  let isArray = Array.isArray(obj)
  let newObj = isArray ? [...obj] : { ...obj }
  Reflect.ownKeys(newObj).forEach((key) => {
    newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
  })

  return newObj
}

let obj = {
  a: [1, 2, 3],
  b: {
    c: 2,
    d: 3,
  },
}
let newObj = deepClone(obj)
newObj.b.c = 1
console.log(obj.b.c) // 2

如有转载或 CV 的请标注本站原文地址