DeepClone — 深拷贝
本文最后更新于252 天前,其中的信息可能已经过时,如有错误请发送邮件到1986413837@qq.com

为什么需要单独实现深拷贝函数?

先看两个现象

const obj1 = { a: { b: { c: 1, d: 2 } } }
const obj2 = obj1
obj2.a = 1
console.log(obj1)
// 输出{ a: 1 }
const obj1 = { a: { b: { c: 1, d: 2 } } }
const obj3 = { ...obj1 }
obj3.a.b = 1
console.log(obj1)
// 输出{ a: { b: 1 } }

我们来详细看一下第二段代码

内存布局如下:

(栈内存 存放基本数据类型​(numberstringbooleannullundefinedsymbolbigint)和引用类型的指针(内存地址)​)

(堆内存 存放引用类型的实际数据​(如 ObjectArrayFunction等))

[栈内存]
obj1 → 0x100 (堆内存地址)
obj3 → 0x200 (堆内存地址)

[堆内存]
0x100: { a → 0x300 }
0x200: { a → 0x300 } // 浅拷贝复制了引用
0x300: { b → 0x400 }
0x400: { c: 1, d: 2 }

图解

修改操作的影响

内存变化过程:

  1. 通过 obj3.a找到 0x300
  2. 修改 0x300.b的值从{ c: 1, d: 2 } 到 1

修改后堆内存

[修改后堆内存]
0x300: 1  // 原始值被修改

最终内存状态

[栈内存]
obj1 → 0x100
obj3 → 0x200

[堆内存]
0x100: { a → 0x300 }
0x200: { a → 0x300 }
0x300: { b: 1 }

1.引用类型的特点

JavaScript 中的对象是引用类型,赋值操作只是复制引用:

const original = { a: 1, b: { c: 2 } };
const copy = original; // 只是引用复制

copy.a = 3;
console.log(original.a); // 3 (原对象也被修改)

2.内置方法无法实现深拷贝

  • Object.assign()和扩展运算符 ...只能浅拷贝
  • JSON.parse(JSON.stringify())有局限性:
const obj = { 
  date: new Date(),
  func: () => console.log('hi'),
  undef: undefined
};

const jsonCopy = JSON.parse(JSON.stringify(obj));
// { date: "2023-05-01T12:00:00.000Z" } 
// 函数和undefined丢失,Date对象转为字符串

3.特殊对象类型的处理

需要单独处理以下类型:

  • Date对象
  • RegExp对象
  • Map/Set集合
  • 函数 (通常选择不拷贝)
  • 循环引用 (对象引用自身)

4.性能与安全考虑

  • 深拷贝是递归操作,需要性能优化
  • 防止拷贝过程中原型链污染
  • 避免意外修改共享的引用数据

怎么实现? 先别想太多

先别想太多 思路很简单 先设置个新的空对象用于拷贝 再遍历原对象的每个key 如果key对应的value 是基础类型那就直接赋值给空对象即可 如果是对象类型那就继续遍历这个对象 —> 这里很明显要递归调用了

代码如下

输出:

{ a: { b: { c: 1, d: 2 } } }
{ a: 1 }

说明已经成功完成深拷贝

想多一点! 代码不太严谨

潜在以下问题

1.无法处理数组

如果 obj是数组,你的代码会错误地把它转成普通对象:

const arr = [1, 2, { a: 3 }];
const clonedArr = deepClone(arr);
console.log(clonedArr); // 输出:{ 0: 1, 1: 2, 2: { a: 3 } }(不是数组!)

修复方法:

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

2.无法处理循环对象

如果对象有循环引用(如 obj.self = obj),会进入无限递归导致栈溢出:

如上图 第10行代码会无限递归执行

const obj = { a: 1 };
obj.self = obj; // 循环引用
deepClone(obj); // 报错:Maximum call stack size exceeded

修复方法:使用 WeakMap缓存已拷贝的对象:

简单介绍一下weakMap:

WeakMap​ 是 JavaScript 中的一种特殊键值对集合,与普通 Map类似,但有以下关键区别:​

键必须是对象​(不能是基本类型:numberstring等)

const deepClone = (obj, cache = new WeakMap()) => {
    if (cache.has(obj)) return cache.get(obj); // 如果已拷贝过,直接返回
    const result = Array.isArray(obj) ? [] : {};
    cache.set(obj, result); // 缓存当前对象
    // ...其余逻辑不变
};

3.无法处理特殊对象(如RegExp, Date, Set, Map)​

如果对象包含 DateRegExp等特殊对象,会被直接当作普通对象拷贝:

const obj = { date: new Date(), regex: /abc/g };
const cloned = deepClone(obj);
console.log(cloned.date); // 输出:普通对象 { ... },而不是 Date 实例

修复方法:特殊处理这些类型

if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);

改进后的最佳实践

function deepClone(obj, cache = new WeakMap()) {
    // 基本类型直接返回
    if (obj === null || typeof obj !== 'object') {
        return obj;
    }

    // 处理循环引用
    if (cache.has(obj)) {
        return cache.get(obj);
    }

    // 处理 Date 对象
    // instanceof:JavaScript 运算符,用于检查左侧对象是否是右侧构造函数的实例
    if (obj instanceof Date) {
        return new Date(obj);
    }

    // 处理 RegExp 对象
    if (obj instanceof RegExp) {
        return new RegExp(obj);
    }

    // 初始化克隆对象(数组 or 普通对象)
    const clone = Array.isArray(obj) ? [] : {};

    // 缓存当前对象,防止循环引用
    cache.set(obj, clone);

    // 克隆普通属性
    for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
            clone[key] = deepClone(obj[key], cache);
        }
    }


    return clone;
}

测试用例

const obj = {
    a: 1,
    b: { c: 2 },
    d: new Date(),
    e: /regex/g,
    f: [1, 2, { g: 3 }]
};
obj.self = obj; // 循环引用

const cloned = deepClone(obj);
console.log(cloned);

输出

{
    a: 1,
    b: { c: 2 },
    d: 2025-09-27T00:00:00.000Z, // Date 类型保留
    e: /regex/g,                  // RegExp 类型保留
    f: [1, 2, { g: 3 }],          // 数组和嵌套对象正确克隆
    self: [Circular]              // 循环引用被正确处理
}

Life's a struggle, I'll conquer it.
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇