JS 深度克隆的实现方法

news2025/1/7 20:37:00

方法一:正统做法(扩展性高,推荐)

function test() {

  this.a = 1;

  this.b = 2;

}

test.prototype.c = 3; // 原型上的属性

const obj = new test();

console.log("原对象", obj);

console.log("克隆后的对象", deepClone(obj));

/** JS 深度克隆
 * @param value 需要克隆的值
 */
function deepClone(value) {
  // 排除原始类型的情况,函数时也满足此条件
  if (typeof value !== "object" || value === null) {
    return value;
  }
  // 克隆结果:1.数组 2.普通对象
  const result = Array.isArray(value) ? [] : {};
  // 设置克隆结果的原型链为 value 的原型链(即保持原型一致)
  Object.setPrototypeOf(result, Object.getPrototypeOf(value));
  // 浅层克隆
  for (const key in value) {
    // 排除原型上的属性
    if (value.hasOwnProperty(key)) {
      result[key] = deepClone(value[key]); // 针对这个对象的每一个属性值进行克隆,则达到深度克隆效果
    }
  }
  return result;
}

解决环形引用问题

function test() {

  this.a = 1;

  this.b = 2;

}

test.prototype.c = 3; // 原型上的属性

const obj = new test();

obj.c = obj; // 环形引用 obj.c 等于 obj 本身

console.log("原对象", obj);

console.log("克隆后的对象", deepClone(obj));

/* 建立缓存区,解决环形引用问题 */
let cache = new WeakMap(); // 使用 WeakMap 为了防止内存泄露

/** JS 深度克隆
 * @param value 需要克隆的值
 */
function deepClone(value) {
  // 排除原始类型的情况,函数时也满足此条件
  if (typeof value !== "object" || value === null) return value;
  // 解决环形引用问题(即循环引用)
  const cached = cache.get(value);
  if (cached) return cached;
  // 克隆结果:1.数组 2.普通对象
  const result = Array.isArray(value) ? [] : {};
  // 设置克隆结果的原型链为 value 的原型链(即保持原型一致)
  Object.setPrototypeOf(result, Object.getPrototypeOf(value));
  // 环形引用时将克隆的值储存到缓存中
  cache.set(value, result);
  // 浅层克隆
  for (const key in value) {
    // 排除原型上的属性
    if (value.hasOwnProperty(key)) {
      result[key] = deepClone(value[key]); // 针对这个对象的每一个属性值进行克隆,则达到深度克隆效果
    }
  }
  return result;
}

方法二:JSON 序列化与反序列化(无扩展性)

const obj = { id: 1, name: "张三", age: 18 };

const newObj = JSON.parse(JSON.stringify(obj));
newObj.name = "艾凯";
newObj.age = 22;

console.log("obj", obj);
console.log("newObj", newObj);

功能上没有问题,但这种做法有一些明显的缺陷。

如果这个对象里面含有 Map 之类的这些玩意,克隆之后这个 mapList 就不再是一个 Map 结构了。

或者是这个对象里面有一些函数之类的,克隆之后这个函数后都没有了。

const obj = { id: 1, name: "张三", age: 18, mapList: new Map(), fun: function () { } };

const newObj = JSON.parse(JSON.stringify(obj));
newObj.name = "艾凯";
newObj.age = 22;

console.log("obj", obj);
console.log("newObj", newObj);

方法三:标签页通信

异步的,比较耗时,没用过

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

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

相关文章

Flume系列:案例-Flume负载均衡和故障转移

目录 Apache Hadoop生态-目录汇总-持续更新 逻辑: 2:案例需求-实现故障转移 3:实现步骤: 2.1:实现flume1.conf 2.2:实现flume2.conf - 端口4141 2.3:实现flume3.conf - 端口4142 3&#…

NIO编程总结

NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,成为解决高并发与大量连接、I/O处理问题…

【如何在Java中使用ForkJoinPool】

目录 背景1.使用ForkJoinPool的线程池2.工作窃取算法3.ForkJoinPool的主要类4.使用递归操作5.资源任务6.何时使用ForkJoinPool7.总结 背景 使用ForkJoinPool去分解计算密集型任务且且并行地执行他们以获得更好的Java应用程序的性能。 ForkJoinPool是一个功能强大的Java类&…

程序员进银行科技岗——简单总结

银行的分类 Top0—中央银行: 仅有一家,即中国人民银行。 Top1—政策性银行: 国家开发银行、中国进出口银行、中国农业发展银行 Top2—国有商业银行: 国有六大行(中国工商银行、中国农业银行、中国银行、中国建设…

【计算机网络】前后端分离,HTTP协议,网络分层结构,TCP

❤️ Author: 老九 ☕️ 个人博客:老九的CSDN博客 🙏 个人名言:不可控之事 乐观面对 😍 系列专栏: 文章目录 前后端分类HTTP协议HTTP组成HTTP的版本HTTP的请求方式HTTP请求头HTTP 响应状态码 AJAX发送请求 …

555定时器的基本原理和应用案例

前言 555定时器常用于脉冲波形的产生和整形电路中,之前在查找555定时器的原理图和基本管脚信息时,网上的内容大多含糊不清,没有讲的很详细,要么只是单一的管脚图,要么就是简单的文字解释,并且大多数缺乏基…

2023 年大厂实习前端面试题(一):跨域问题

1. 跨域 1.1 跨域问题来源 跨域问题的来源是浏览器为了请求安全而引入的基于同源策略(Same-origin policy)的安全特性。 同源策略是浏览器一个非常重要的安全策略,基于这个策略可以限制非同源的内容与当前页面进行交互,从而减少…

linux 条件变量 pthread_cond_signal

专栏内容:linux下并发编程个人主页:我的主页座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物. 目录 前言 简介 应用场景 与互斥量/信号量的区别 接口介绍 变量定义 初始化 等待被唤…

ROS:ROS的一些基本命令行

目录 一、打开小海龟1.1终端,启动ROS Master:1.2终端2,启动小海龟仿真器:1.3终端3,启动海龟控制节点: 二、查看系统中的计算图三、节点命令3.1查看节点下的命令rosnode3.2显示节点列表rosnode list3.3查看节…

[CISCN2023]unzip

[CISCN2023]unzip 环境搭建 1.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body><form method"post" action"1.php" en…

Java 基础进阶篇(十六):多线程总结

文章目录 一、多线程概述二、多线程的创建1.1 方式一&#xff1a;继承 Thread 类1.2 方式二&#xff1a;实现 Runnable 接口匿名内部类实现方案 1.3 方式三&#xff1a;JDK 5.0新增: 实现 Callable 接口1.4 三种方式对比 二、Thread的常用方法三、线程安全与同步3.1 线程安全3.…

数据类型.

数据类型 数据类型分类 数值类型 tinyint类型 数值越界测试&#xff1a; mysql> create table tt1(num tinyint); Query OK, 0 rows affected (0.02 sec)mysql> insert into tt1 values(1); Query OK, 1 row affected (0.00 sec)mysql> insert into tt1 values(128…

数据仓库基础(通俗易懂,好文)数仓概念

1、数据仓库的概念 数据仓库&#xff08;英语&#xff1a;Data Warehouse&#xff0c;简称数仓、DW&#xff09;,是一个用于存储、分析、报告的数据系统。数据仓库的目的是构建面向分析的集成化数据环境&#xff0c;为企业提供决策支持&#xff08;Decision Support&#xff09…

CISCN WP ——R3vCr4ck

[CISCN-Misc] 签到卡 [CISCN-Misc] 被加密的生产流量 在过滤器中搜索modbus 发现类似base的编码 跟踪TCP流得到Base32密文 在线解密 [CISCN-Crypto]可信度量 非预期解 分析题目&#xff0c;发现修改程序后的测试程序位于容器内&#xff0c;使用winscp通过scp连接容器&#xff…

Flume系列:案例-Flume复制(Replicating)和多路复用(Multiplexing)

目录 Apache Hadoop生态-目录汇总-持续更新 1&#xff1a;案例流程描述 2&#xff1a;实现步骤&#xff1a; 2.1&#xff1a;实现flume1.conf 2.2&#xff1a;实现flume2_hdfs.conf 2.3&#xff1a;实现flume3_dir.conf 3&#xff1a;启动传输链路 Apache Hadoop生态-目录…

移动端开发之基础知识

移动端开发之流式布局 移动端基础浏览器现状手机屏幕现状移动端调试方法 视口布局视口视觉视口理想视口总结&#xff1a; meta视口标签标准的viewport设置 三倍图物理像素&物理像素比多倍图背景缩放 background-size背景图三倍图 多倍图切图 cutterman 移动端开发选择移动端…

这么可爱的彩虹屁老婆,真的不想“娶”一个放桌面上吗?

&#x1f4a7;这么可爱的 彩虹屁老婆 \color{#FF1493}{彩虹屁老婆} 彩虹屁老婆&#xff0c;真的不想“娶”一个放桌面上吗&#xff1f;&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f984; 个人主页——微风撞见云的博客&#x1f390; &…

如何在华为OD机试中获得满分?Java实现【比赛评分】一文详解!

✅创作者:陈书予 🎉个人主页:陈书予的个人主页 🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区 🌟专栏地址: Java华为OD机试真题(2022&2023) 文章目录 1. 题目描述2. 输入描述3. 输出描述4. Java算法源码5. 测试6.解题思路1. 题目描述 一个有N个选手参加比赛,…

信号处理与分析-卷积的性质与推导

目录 一、引言 二、信号分析中的卷积 1. 什么是卷积 2. 卷积的性质 3. 卷积的应用 三、离散卷积 1. 离散卷积的定义 2. 离散卷积的计算 3. 离散卷积的性质 四、连续卷积 五、卷积的实际应用 六、总结 一、引言 在信号处理中&#xff0c;卷积是一种非常重要的数学运…

如何在华为OD机试中获得满分?Java实现【吃到最多的刚好合适的菜】一文详解!

✅创作者:陈书予 🎉个人主页:陈书予的个人主页 🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区 🌟专栏地址: Java华为OD机试真题(2022&2023) 文章目录 1. 题目描述2. 输入描述3. 输出描述4. Java算法源码5. 测试6.解题思路1. 题目描述 入职后,导师会请你吃饭…