当前位置: 首页 > news >正文

JavaScript 深拷贝:从基础到完美实现

深拷贝是 JavaScript 开发中常见的需求,本文将带你从基础概念开始,逐步深入,最终实现一个完美的深拷贝函数。

一、浅拷贝 vs 深拷贝

1. 浅拷贝

浅拷贝只复制对象的第一层属性,更深层次的属性仍然是共享的。

const obj = { a: 1, b: { c: 2 } };
const shallowCopy = { ...obj };shallowCopy.b.c = 3;
console.log(obj.b.c); // 3 - 原对象也被修改了

2. 深拷贝

深拷贝会递归复制对象的所有层级,创建完全独立的副本。

const obj = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(obj));deepCopy.b.c = 3;
console.log(obj.b.c); // 2 - 原对象不受影响

局限性:

  • 不能处理函数、undefined、Symbol
  • 不能处理循环引用
  • 会丢失 Date 对象(转为字符串)
  • 会丢失 RegExp 对象
  • 会丢失原型链

2. 递归实现(基础版)

function deepClone(obj) {if (obj === null || typeof obj !== 'object') {return obj;}let clone = Array.isArray(obj) ? [] : {};for (let key in obj) {if (obj.hasOwnProperty(key)) {clone[key] = deepClone(obj[key]);}}return clone;
}

问题:无法处理循环引用

三、处理循环引用

function deepClone(obj, hash = new WeakMap()) {if (obj === null || typeof obj !== 'object') {return obj;}// 处理循环引用if (hash.has(obj)) {return hash.get(obj);}let clone = Array.isArray(obj) ? [] : {};hash.set(obj, clone);for (let key in obj) {if (obj.hasOwnProperty(key)) {clone[key] = deepClone(obj[key], hash);}}return clone;
}

四、处理特殊对象

1. 处理 Date 和 RegExp

function deepClone(obj, hash = new WeakMap()) {if (obj === null || typeof obj !== 'object') {return obj;}// 处理特殊对象if (obj instanceof Date) return new Date(obj);if (obj instanceof RegExp) return new RegExp(obj);if (hash.has(obj)) return hash.get(obj);//自定义对象处理let clone = new obj.constructor();hash.set(obj, clone);for (let key in obj) {if (obj.hasOwnProperty(key)) {clone[key] = deepClone(obj[key], hash);}}return clone;
}

2. 处理 Map 和 Set

function deepClone(obj, hash = new WeakMap()) {// ...前面的代码...if (obj instanceof Map) {const clone = new Map();hash.set(obj, clone);obj.forEach((value, key) => {clone.set(deepClone(key, hash), deepClone(value, hash));});return clone;}if (obj instanceof Set) {const clone = new Set();hash.set(obj, clone);obj.forEach(value => {clone.add(deepClone(value, hash));});return clone;}// ...后面的代码...
}

五、处理 Symbol 属性和原型链

function deepClone(obj, hash = new WeakMap()) {// 处理原始值和nullif (Object(obj) !== obj || obj === null) return obj;// 处理特殊对象if (obj instanceof Date) return new Date(obj);if (obj instanceof RegExp) return new RegExp(obj);if (obj instanceof Map) {const clone = new Map();hash.set(obj, clone);obj.forEach((value, key) => {clone.set(deepClone(key, hash), deepClone(value, hash));});return clone;}if (obj instanceof Set) {const clone = new Set();hash.set(obj, clone);obj.forEach(value => {clone.add(deepClone(value, hash));});return clone;}// 处理循环引用if (hash.has(obj)) return hash.get(obj);// 获取所有属性,包括Symbolconst allKeys = Reflect.ownKeys(obj);// 获取原型const proto = Object.getPrototypeOf(obj);// 创建新对象,保持原型链const clone = Object.create(proto);hash.set(obj, clone);// 复制所有属性allKeys.forEach(key => {clone[key] = deepClone(obj[key], hash);});return clone;
}

六、最终完美实现

function deepClone(obj, hash = new WeakMap()) {// 处理原始值和nullif (Object(obj) !== obj || obj === null) return obj;// 处理特殊对象if (obj instanceof Date) return new Date(obj);if (obj instanceof RegExp) return new RegExp(obj);if (obj instanceof Map) {const clone = new Map();hash.set(obj, clone);obj.forEach((value, key) => {clone.set(deepClone(key, hash), deepClone(value, hash));});return clone;}if (obj instanceof Set) {const clone = new Set();hash.set(obj, clone);obj.forEach(value => {clone.add(deepClone(value, hash));});return clone;}if (obj instanceof ArrayBuffer) return obj.slice(0);if (ArrayBuffer.isView(obj)) {return new obj.constructor(deepClone(obj.buffer, hash),obj.byteOffset,obj.byteLength);}// 处理循环引用if (hash.has(obj)) return hash.get(obj);// 处理普通对象和数组const proto = Object.getPrototypeOf(obj);const clone = Object.create(proto);hash.set(obj, clone);// 复制Symbol属性和普通属性Reflect.ownKeys(obj).forEach(key => {clone[key] = deepClone(obj[key], hash);});const allDesc = Object.getOwnPropertyDescriptors(obj)const result = Object.create(Object.getPrototypeOf(obj), allDesc)hash.set(obj, result)return clone;
}

WeakMap 的基本作用

WeakMap 是 JavaScript 中的一种特殊集合类型,与普通 Map 的主要区别在于:

键必须是对象(不能是原始值)

键是弱引用(不会阻止垃圾回收)

不可枚举(没有方法能获取所有键)

解决循环拷贝问题

在实现深拷贝时,遇到循环引用(对象属性间接或直接引用自身)会导致无限递归。WeakMap 可以优雅地解决这个问题:

解决方案原理
跟踪已拷贝对象:使用 WeakMap 记录原始对象和其拷贝的对应关系

遇到已拷贝对象直接返回:避免无限递归

自动内存管理:WeakMap 的弱引用特性不会阻止原始对象被垃圾回收

http://www.dtcms.com/a/310449.html

相关文章:

  • 使用Jeecg低代码平台实现计划管控系统建设方案--1项目前后端搭建
  • 《义龙棒球科普》棒球是韩国的国球吗·棒球1号位
  • 德国威乐集团亚太中东非洲PMO负责人和继明受邀为PMO大会主持人
  • 逻辑回归算法 银行贷款资格判断案例,介绍混淆矩阵与正则化惩罚
  • Google机器学习基础(语言模型)
  • 第13届蓝桥杯Python青少组选拔赛(STEMA)2021年8月真题
  • osloader!DoGlobalInitialization函数分析之HW_CURSOR--NTLDR源代码分析之设置光标
  • Python编程基础与实践
  • Linux 用户与组管理及权限委派
  • 自由学习记录(75)
  • [2025CVPR-图象处理方向]Z-Magic:零样本多属性引导图像创建器
  • SpringBoot与Rust实战指南
  • 深度SEO优化的方式有哪些,从技术层面来说
  • GitHub 趋势日报 (2025年07月31日)
  • 【实战】Dify从0到100进阶--插件开发(1)Github爬取插件
  • ansible.cfg 配置文件生成
  • [css]切角
  • 第十四天:C++内存管理
  • Agents-SDK智能体开发[2]之工具调用
  • Nginx 来正确地托管网站服务
  • 《软件测试与质量控制》实验报告一 测试用例设计
  • 自动化框架pytest
  • 小学阶段的学习机推荐:科大讯飞T30、Lumie 10学习机暑期16项AI功能升级
  • 2025电赛G题-发挥部分-参数自适应FIR滤波器
  • python列表推导式
  • uniapp基础 (二)
  • 电商作图,商品图、模特图、促销海报设计
  • Unity优化技巧:自动隐藏视野外的3D模型
  • 【人工智能-16】机器学习:概念、工具介绍、数据集、特征工程
  • 铁皮矫平机进阶小百科