跳至主要內容

5. 深拷贝

鸭梨小于 1 分钟

5. 深拷贝

浅拷贝:

/* eslint-disable no-prototype-builtins */
export function shallowCopy(obj) {
  if (typeof obj !== 'object')
    return

  const newObj = Array.isArray(obj) ? [] : {}
  for (const key in obj) {
    if (obj.hasOwnProperty(key))
      newObj[key] = obj[key]
  }
  return newObj

简单的深拷贝,只考虑普通对象属性,不考虑内置对象和函数,不能解决循环引用问题:


export function deepClone(obj) {
  if (typeof obj !== 'object')
    return
  const newObj = Array.isArray(obj) ? [] : {}
  for (const key in obj) {
    if (obj.hasOwnProperty(key))
      newObj[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key]
  }
  return newObj

复杂版深拷贝:基于简单版的基础上,还考虑了内置对象比如 DateRegExp 等对象和函数以及解决了循环引用的问题:

/* eslint-disable no-prototype-builtins */
const isObject = target => (typeof target === 'object' || typeof target === 'function') && target !== null

export function deepClone(target, map = new WeakMap()) {
  if (map.get(target))
    return target

  // 获取当前值的构造函数:获取它的类型
  const constructor = target.constructor
  // 检测当前对象 target 是否与正则、日期格式对象匹配
  if (/^(RegExp|Date)$/i.test(constructor.name)) {
    // 创建一个新的特殊对象(正则类/日期类)的实例
    return new constructor(target)
  }
  if (isObject(target)) {
    map.set(target, true) // 为循环引用的对象做标记
    const cloneTarget = Array.isArray(target) ? [] : {}
    for (const prop in target) {
      if (target.hasOwnProperty(prop))
        cloneTarget[prop] = deepClone(target[prop], map)
    }
    return cloneTarget
  }
  else {
    return target
  }
}