最详细实现一个深拷贝函数

1,723 阅读2分钟

很多小伙伴面试的时候遇到过手写深拷贝的题目,这篇文章将从基本类型、对象类型、特殊对象类型三种情况出发,实现一个简单的深拷贝函数,让各位小伙伴彻底摆脱深拷贝这个难题,实现代码在最下面,复制下来所有的函数代码可直接运行。

针对不同的值的拷贝方式

基本类型

  • Null
  • Number
  • Boolean
  • String
  • Undefined
any => any

对象类型

any => {
    // 创建一个普通对象
    const o = new Object()
    // 复制any所有的属性到o上,实现方式在下面
    copyOwnProperties(any, o)
    return o
}

特殊的对象类型

日期类型

any => new Date(any)

正则类型

any => new Regex(any)

函数类型

any => {
    // 创建一个函数对象
    const o = new Function("return " + any.toString())()
    // 复制any所有的属性到o上,实现方式在下面
    copyOwnProperties(any, o)
    return o
}

数组类型

any => {
    // 创建一个数组对象
    const o = new Array()
    // 复制any所有的属性到o上,实现方式在下面
    copyOwnProperties(any, o)
    return o
}

实现一个完整的深拷贝函数

TypeOf

// 获取数据类型
function typeOf(any) {
  return Object.prototype.toString.call(any).split(' ')[1].slice(0, -1)
}

copyOwnProperties

// 复制from的属性到to上,cache保存已复制属性引用,防止重复引用
function copyOwnProperties(from, to, cache) {
  const names = Object.getOwnPropertyNames(from)
  for (let name of names) {
    const descriptor = Object.getOwnPropertyDescriptor(from, name)
    Object.defineProperty(to, name, { ...descriptor, value: recursionClone(descriptor.value, cache) })
  }

  return to
}

recursionClone

// 根据不同类型的数据进行不同的拷贝方式,cache保存已复制属性引用,防止重复引用
function recursionClone(any, cache) {
  const typ = typeOf(any)

  if (['String', 'Number', 'Null', 'Boolean', 'Undefined'].includes(typ)) {
    return any
  }

  if (!cache) {
    cache = new Map()
  }

  if (cache.get(any)) {
    return cache.get(any)
  }

  if (typ === 'RegExp') {
    return new RegExp(any)
  }

  if (typ === 'Date') {
    return new Date(any)
  }

  let O
  if (typ === 'Function') {
    O = (new Function('return ' + any.toString()))()
  }

  if (typ === 'Array') {
    O = new Array()
  }

  if (typ === 'Object') {
    O = new Object()
  }

  if (O) {
    cache.set(any, O)
    copyOwnProperties(any, O, cache)
    return O
  }

  return null
}

deepClone

function deepClone(any) {
    return recursionClone(any)
}

总结

  • 基本类型直接拷贝
  • 对象类型递归拷贝,缓存已拷贝值,防止互相引用
  • Function、Array、Date、Regex类型进行特殊处理