ES6 深克隆与浅克隆详解:原理、实现与应用场景

news2025/6/6 12:21:51

ES6 深克隆与浅克隆详解:原理、实现与应用场景

一、克隆的本质与必要性

在 JavaScript 中,数据分为两大类型:

  • 基本类型:Number、String、Boolean、null、undefined、Symbol、BigInt
  • 引用类型:Object、Array、Function、Date、RegExp 等

克隆的必要性

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

original.a = 10;
console.log(copy.a); // 10 - 修改影响副本

original.b.c = 20;
console.log(copy.b.c); // 20 - 深层修改也影响副本

二、浅克隆(Shallow Clone)

1. 概念与特点

  • 只复制对象的第一层属性
  • 嵌套对象仍然是引用关系
  • 适用于简单对象结构

2. ES6 实现方式

2.1 扩展运算符(…)
const obj = { a: 1, b: { c: 2 } };
const shallowClone = { ...obj };

obj.b.c = 3;
console.log(shallowClone.b.c); // 3(受影响)
2.2 Object.assign()
const arr = [1, 2, { d: 4 }];
const arrClone = Object.assign([], arr);

arr[2].d = 5;
console.log(arrClone[2].d); // 5(受影响)
2.3 Array.slice()
const original = [1, { name: 'Alice' }];
const clone = original.slice();

original[1].name = 'Bob';
console.log(clone[1].name); // 'Bob'(受影响)

3. 使用场景

  • 组件 props 传递配置对象
  • 状态管理中的状态快照
  • 简单数据结构的临时拷贝

三、深克隆(Deep Clone)

1. 概念与特点

  • 递归复制对象的所有层级
  • 创建完全独立的内存副本
  • 修改原对象不影响克隆对象

2. 手动实现深克隆

基础递归实现:
function deepClone(source) {
  // 基本类型直接返回
  if (source === null || typeof source !== 'object') {
    return source;
  }
  
  // 处理数组
  if (Array.isArray(source)) {
    return source.map(item => deepClone(item));
  }
  
  // 处理对象
  const clone = {};
  for (const key in source) {
    if (source.hasOwnProperty(key)) {
      clone[key] = deepClone(source[key]);
    }
  }
  
  return clone;
}

// 测试
const obj = { a: 1, b: { c: 2 } };
const deepCopy = deepClone(obj);

obj.b.c = 3;
console.log(deepCopy.b.c); // 2(不受影响)
增强版(处理特殊对象):
function enhancedDeepClone(source, map = new WeakMap()) {
  // 基本类型直接返回
  if (source === null || typeof source !== 'object') {
    return source;
  }
  
  // 处理循环引用
  if (map.has(source)) return map.get(source);
  
  // 特殊对象处理
  switch (source.constructor) {
    case Date:
      return new Date(source);
    case RegExp:
      return new RegExp(source);
    case Set:
      return new Set([...source].map(item => enhancedDeepClone(item, map)));
    case Map:
      return new Map([...source].map(([k, v]) => 
        [enhancedDeepClone(k, map), enhancedDeepClone(v, map)]
      ));
    case ArrayBuffer:
      return source.slice(0);
  }
  
  // 普通对象和数组
  const clone = Array.isArray(source) ? [] : {};
  map.set(source, clone);
  
  // 处理Symbol键
  const symbolKeys = Object.getOwnPropertySymbols(source);
  const allKeys = [...Object.keys(source), ...symbolKeys];
  
  for (const key of allKeys) {
    clone[key] = enhancedDeepClone(source[key], map);
  }
  
  return clone;
}

3. JSON 序列化法(有局限)

const obj = {
  date: new Date(),
  regex: /pattern/g,
  func: () => console.log('test')
};

const jsonClone = JSON.parse(JSON.stringify(obj));

console.log(jsonClone);
// {
//   date: "2023-08-15T12:00:00.000Z", // Date转为字符串
//   regex: {},                        // RegExp变为空对象
//   func: null                        // 函数丢失
// }

JSON方法的缺陷

  1. 丢失函数属性
  2. 忽略Symbol键
  3. Date对象转为字符串
  4. RegExp变为空对象
  5. 无法处理循环引用
  6. 忽略undefined值

4. 现代浏览器原生API:structuredClone()

const obj = {
  date: new Date(),
  regex: /pattern/g,
  array: [1, 2, 3],
  set: new Set([4, 5, 6])
};

const clone = structuredClone(obj);

console.log(clone);
// {
//   date: Date, // 保持Date对象
//   regex: /pattern/g, // 保持正则
//   array: [1,2,3],
//   set: Set(3) {4,5,6}
// }

支持的数据类型

  • 原始值
  • Array/ArrayBuffer
  • Map/Set
  • Date/RegExp
  • Blob/File/FileList
  • ImageData/ImageBitmap
  • 错误类型(Error, EvalError等)
  • 对象字面量(仅包含以上类型)

不支持的类型

  • Function
  • DOM节点
  • 对象方法
  • 属性描述符/getter/setter
  • 原型链

四、深克隆性能优化

1. 循环引用处理

function deepClone(source, map = new WeakMap()) {
  // ... 其他代码
  if (map.has(source)) {
    return map.get(source);
  }
  
  const target = new constructor();
  map.set(source, target);
  
  // ... 克隆逻辑
}

2. 非递归实现(栈代替递归)

function deepCloneStack(source) {
  const stack = [];
  const map = new WeakMap();
  
  const target = new source.constructor();
  stack.push([source, target]);
  map.set(source, target);
  
  while (stack.length) {
    const [current, parent] = stack.pop();
    
    for (const key in current) {
      if (current.hasOwnProperty(key)) {
        const value = current[key];
        
        // 基本类型直接赋值
        if (value === null || typeof value !== 'object') {
          parent[key] = value;
          continue;
        }
        
        // 处理循环引用
        if (map.has(value)) {
          parent[key] = map.get(value);
          continue;
        }
        
        // 创建新对象
        const child = new value.constructor();
        parent[key] = child;
        map.set(value, child);
        stack.push([value, child]);
      }
    }
  }
  
  return target;
}

五、应用场景与最佳实践

1. 浅克隆适用场景

  • 组件 props 传递配置对象
  • Redux reducer 中的状态更新
  • 函数参数中的对象扩展
  • 无嵌套结构的简单数据对象
// Vue 组件 props 解构
export default {
  props: ['config'],
  setup(props) {
    const localConfig = { ...props.config }; // 浅克隆
  }
}

2. 深克隆必要场景

  • 状态管理中的初始状态快照
  • 需要完全隔离的缓存数据
  • 撤销/重做功能实现
  • 复杂配置对象的版本管理
  • Web Worker 数据传输
// 在 Web Worker 中处理数据
worker.postMessage(structuredClone(largeDataSet));

3. 现代框架中的克隆实践

Vue 状态管理:
// 使用深克隆创建初始状态
const initialState = deepClone(fetchedData);

// 在组件中使用
export default {
  data() {
    return {
      localState: deepClone(this.initialState)
    }
  }
}
React 状态更新:
function reducer(state, action) {
  switch (action.type) {
    case 'UPDATE_USER':
      // 深合并示例
      return {
        ...state,
        user: {
          ...state.user,
          ...action.payload
        }
      };
      
    case 'ADD_ITEM':
      // 数组深克隆
      return {
        ...state,
        items: [...state.items, action.item]
      };
  }
}

六、克隆方案选择指南

场景特征推荐方案原因说明
简单对象无嵌套浅克隆性能最优
需要保留特殊对象类型structuredClone()原生支持多种类型
包含函数/循环引用lodash.cloneDeep完整处理复杂情况
现代浏览器环境structuredClone()原生性能最好
需要处理DOM节点自定义实现需特殊处理DOM API
超大对象(>10MB)分块克隆避免阻塞主线程
高频克隆操作(>1000次/秒)浅克隆+immutable性能敏感场景优化

七、总结与最佳实践

  1. 理解数据本质:区分基本类型和引用类型
  2. 明确克隆需求:深克隆还是浅克隆
  3. 选择合适方案
    • 优先使用浏览器原生API:structuredClone()
    • 复杂场景使用成熟库:lodash的_.cloneDeep()
    • 特殊需求自定义实现
  4. 处理边界情况
    • 循环引用使用WeakMap
    • 特殊对象类型单独处理
    • Symbol属性不能忽略
  5. 性能考量
    • 避免在循环中深度克隆大对象
    • 考虑使用不可变数据结构
    • 超大对象使用分块处理
// 最佳实践示例
import { cloneDeep } from 'lodash-es';

// 需要完全隔离的数据
const configBackup = cloneDeep(runtimeConfig);

// 浏览器环境简单克隆
const stateSnapshot = structuredClone(appState);

// 浅克隆配置对象
const currentSettings = { ...defaultSettings, ...userSettings };

掌握深浅克隆的区别和实现方式,是写出健壮JavaScript应用的关键技能。根据具体场景选择合适的克隆策略,可以有效避免数据污染和意外行为。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2399468.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

153页PPT麦肯锡咨询流程管理及企业五年发展布局构想与路径规划

麦肯锡咨询的流程管理以其高度结构化、数据驱动和结果导向的核心特点著称,旨在为客户提供清晰、可行且价值最大化的解决方案。其典型流程可概括为以下几个关键阶段:下载资料请查看文章中图片右下角信息 问题界定与结构化: 这是流程的基石。麦…

[特殊字符] 革命性AI提示词优化平台正式开源!

AI时代最强大的Prompt工程师已经到来! 你是否还在为写不出高质量提示词而头疼?是否羡慕那些能够驾驭AI、让ChatGPT、Claude乖乖听话的"提示词大师"?今天,我们为你带来一个颠覆性的解决方案——TokenAI Auto-Prompt&…

我的概要设计模板(以图书管理系统为例)

一、总述 1.1 需求或目标 随着数字化阅读普及,传统图书馆管理方式效率低下、资源检索不便。为提升图书管理效率,方便读者借阅与查询,公司计划开发 “在线图书管理系统”,实现图书的电子化管理、快速检索、在线借阅等功能&#x…

DrissionPage爬虫包实战分享

一、爬虫 1.1 爬虫解释 爬虫简单的说就是模拟人的浏览器行为,简单的爬虫是request请求网页信息,然后对html数据进行解析得到自己需要的数据信息保存在本地。 1.2 爬虫的思路 # 1.发送请求 # 2.获取数据 # 3.解析数据 # 4.保存数据 1.3 爬虫工具 Dris…

iptables实战案例

目录 一、实验拓扑 二、网络规划 三、实验要求 四、环境准备 1.firewall (1)配置防火墙各大网卡IP并禁用 firewall和selinux (2)打开firewall路由转发 2.PC1(内网) (1)配置防…

Google AI 模式下的SEO革命:生成式搜索优化(GEO)与未来营销策略

一、搜索范式转变:从链接引导到答案交付 Google自2023年起逐步推出AI搜索功能,经历了SGE(Search Generative Experience)和Gemini阶段,最终在2025年全面上线了「AI Mode」搜索模式。与此同时,也保留了一种过…

SpringBoot中缓存@Cacheable出错

SpringBoot中使用Cacheable: 错误代码&#xff1a; Cacheable(value "FrontAdvertiseVOList", keyGenerator "cacheKey") Override public List<FrontAdvertiseVO> getFrontAdvertiseVOList(Integer count) {return this.list(Wrappers.<Adve…

iOS UIActivityViewController 组头处理

0x00 情形一 - (void)shareAction1 {// 当前 View 转成图片UIImage *image [self snapshotImage:self.view];NSArray *activityItems [image];UIActivityViewController *activityVC [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationAc…

《TCP/IP 详解 卷1:协议》第3章:链路层

以太网和IEEE802局域网/城域网标准 IEEE802局域网/城域网标准 IEEE 802 是一组由 IEEE&#xff08;电气与电子工程师协会&#xff09;定义的局域网和城域网通信标准系列&#xff0c;涵盖了从物理层到链路层的多个网络技术。其中&#xff1a; IEEE 802.3 定义的是传统的以太网…

Elasticsearch从安装到实战、kibana安装以及自定义IK分词器/集成整合SpringBoot详细的教程(二)

package com.test.xulk.es.entity.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.test.xulk.es.entity.Hotel;public interface HotelMapper extends BaseMapper<Hotel> { }集成Springboot 项目里面 官方地址&#xff1a; Elasticsearch …

数据库管理-第333期 Oracle 23ai:RAC打补丁完全不用停机(20250604)

数据库管理333期 2025-06-04 数据库管理-第333期 Oracle 23ai&#xff1a;RAC打补丁完全不用停机&#xff08;20250604&#xff09;1 概念2 要求3 操作流程4 转移失败处理总结 数据库管理-第333期 Oracle 23ai&#xff1a;RAC打补丁完全不用停机&#xff08;20250604&#xff0…

【DAY39】图像数据与显存

内容来自浙大疏锦行python打卡训练营 浙大疏锦行 知识点&#xff1a; 图像数据的格式&#xff1a;灰度和彩色数据模型的定义显存占用的4种地方 模型参数梯度参数优化器参数数据批量所占显存神经元输出中间状态 batchisize和训练的关系 作业&#xff1a;今日代码较少&#xff0…

AI代码库问答引擎Folda-Scan

简介 什么是 Folda-Scan &#xff1f; Folda-Scan 是一款革命性的智能项目问答工具&#xff0c; 完全在浏览器中本地运行 。它使用高级语义矢量化将您的代码库转变为对话伙伴&#xff0c;使代码理解和 AI 协作变得前所未有的简单和安全。其采用尖端的 Web 技术和 AI 算法构建&…

Kafka深度技术解析:架构、原理与最佳实践

一、 消息队列的本质价值与核心特性 1.1 分布式系统的“解耦器” 异步通信模型 代码列表 graph LRA[生产者] -->|异步推送| B[(消息队列)]B -->|按需拉取| C[消费者1]B -->|按需拉取| D[消费者2] 生产者发送后立即返回&#xff0c;消费者以自己的节奏处理消息。典…

基于cnn的通用图像分类项目

背景 项目上需要做一个图像分类的工程。本人希望这么一个工程可以帮助学习ai的新同学快速把代码跑起来&#xff0c;快速将自己的数据集投入到实战中&#xff01; 代码仓库地址&#xff1a;imageClassifier: 图片分类器 数据处理 自己准备的分类图像&#xff0c;按照文件夹分…

Linux环境管道通信介绍

目录 前言 一、通信的本质 二、匿名管道 1.通信资源——文件缓冲区 2.为什么叫匿名管道&#xff1f; ​编辑 3.匿名管道的创建过程 4.pipe函数 小结 5.一些问题 1&#xff09;匿名管道为什么要求父子进程将原本的读/写权限只保留一个 2&#xff09;为什么一开始父进程要以读/写…

DIC技术助力金属管材全场应变测量:高效解决方案

在石油管道、汽车排气系统、航空航天液压管路等工业场景中&#xff0c;金属管作为关键承力部件&#xff0c;其拉伸性能&#xff08;如弹性极限、颈缩行为、断裂韧性&#xff09;直接影响结构安全性和使用寿命。 实际应用中&#xff0c;选用合适的管材非常重要&#xff0c;通过…

嵌入式学习--江协stm32day1

失踪人口回归了&#xff0c;stm32的学习比起51要慢一些&#xff0c;因为涉及插线&#xff0c;可能存在漏插&#xff0c;不牢固等问题。 相对于51直接对寄存器的设置&#xff0c;stm32因为是32位修改起来比较麻烦&#xff0c;江协课程是基于标准库的&#xff0c;是对封装函数进…

湖北理元理律师事务所:债务化解中的心理重建与法律护航

专业法律顾问视角 一、债务危机的双重属性&#xff1a;法律问题与心理困境 在对173名债务人的调研中发现&#xff1a; 68%存在焦虑引发的决策障碍&#xff08;如不敢接听银行电话&#xff09; 42%因羞耻感隐瞒债务导致雪球效应 湖北理元理律师事务所创新采用法律-心理双轨…

【更新中】(文档+代码)基于推荐算法和Springboot+Vue的购物商城

概要设计 本节规划和定义了Woodnet桌游电商平台的软件概要设计说明书&#xff0c;描述了软件的总体设计、接口设计、运行设计、系统数据库结构设计以及系统出错处理设计&#xff0c;从整体上说明了系统设计的结构层次、处理流程、系统用例等。 本系统是一个独立的系统&#x…