如何实现对象的深拷贝

7 阅读2分钟

在前端开发中(你平时用 Vue3 + TS,这个问题面试也非常高频),深拷贝是必问知识点。

我给你从 ⭐ 面试级讲解 + ⭐ 实战可用代码 两个层面讲清楚。


一、什么是深拷贝?

const obj = {
  name: "chenjie",
  info: {
    age: 18
  }
}

❌ 浅拷贝

const copy = { ...obj }
copy.info.age = 20
console.log(obj.info.age) // 20

👉 内层对象共享引用


✅ 深拷贝

copy.info.age = 20
console.log(obj.info.age) // 18

👉 所有层级都完全复制


二、常见实现方式(面试必答)


1️⃣ JSON 方式(最简单)

const deepClone = (obj) => {
  return JSON.parse(JSON.stringify(obj))
}

优点

  • 简单
  • 够用

缺点(面试加分点)

不能处理:

  • undefined
  • function
  • Symbol
  • Date
  • RegExp
  • Map / Set
  • 循环引用
  • BigInt

👉 面试时说这几点,基本加分。


2️⃣ structuredClone(现代推荐)

const copy = structuredClone(obj)

优点

  • 浏览器原生
  • 支持 Map / Set / Date
  • 支持循环引用
  • 比 JSON 强很多

缺点

  • 低版本浏览器不支持

👉 现在新项目优先推荐


3️⃣ 手写递归版本(面试高频)

这是你必须会写的 👇

function deepClone(obj, hash = new WeakMap()) {
  if (obj === null) return null

  if (typeof obj !== "object") {
    return obj
  }

  // 解决循环引用
  if (hash.has(obj)) {
    return hash.get(obj)
  }

  const cloneObj = Array.isArray(obj) ? [] : {}

  hash.set(obj, cloneObj)

  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      cloneObj[key] = deepClone(obj[key], hash)
    }
  }

  return cloneObj
}

三、进阶版(支持 Date、RegExp)

面试中高级一点的写法:

function deepClone(obj, hash = new WeakMap()) {
  if (obj === null) return null

  if (obj instanceof Date) {
    return new Date(obj)
  }

  if (obj instanceof RegExp) {
    return new RegExp(obj)
  }

  if (typeof obj !== "object") {
    return obj
  }

  if (hash.has(obj)) {
    return hash.get(obj)
  }

  const cloneObj = Array.isArray(obj) ? [] : {}

  hash.set(obj, cloneObj)

  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      cloneObj[key] = deepClone(obj[key], hash)
    }
  }

  return cloneObj
}

四、Vue 项目中要不要自己写?

⚠️ 在 Vue3 项目里要注意:

  • 响应式对象不能随便 JSON
  • Proxy 会丢失响应式

如果你只是:

const data = reactive({...})

想要普通对象:

import { toRaw } from "vue"

const raw = toRaw(data)
const copy = structuredClone(raw)

五、面试标准回答模板(你可以直接背)

如果面试官问:

你怎么实现深拷贝?

你可以这样答:

  1. 简单场景我会用 JSON.parse(JSON.stringify())
  2. 如果需要支持循环引用、Map、Set,我会用 structuredClone
  3. 面试手写的话,我会用递归 + WeakMap 解决循环引用
  4. 生产环境推荐 structuredClone

六、性能对比(面试加分)

一般性能排序:

structuredClone > 手写递归 > JSON

但真实情况取决于数据结构。


七、总结一张表(重点记)

方法是否推荐支持循环引用支持Date面试
JSON简单场景基础
structuredClone⭐⭐⭐⭐进阶
手写递归⭐⭐⭐可扩展必会

如果你愿意,我可以给你:

  • ✅ 一份「前端面试高频手写题完整版」
  • ✅ 或者带你从源码角度分析 lodash 的 cloneDeep
  • ✅ 或者讲讲 Vue 响应式为什么不能随便深拷贝

你想往哪个方向深入?