JS 深度克隆的实现方法

news/2024/11/7 22:47:16/

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

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.ppmy.cn/news/99894.html

相关文章

C# | 凸包算法之Andrew‘s,获取围绕一组点的凸多边形的轮廓点

C#实现凸包算法之Andrew’s 文章目录 C#实现凸包算法之Andrews前言示例代码实现思路测试结果结束语 前言 这篇关于凸包算法的文章,本文使用C#和Andrew’s算法来实现凸包算法。 首先消除两个最基本的问题: 什么是凸包呢? 凸包是一个包围一组…

个人博客-SpringBoot+Vue3项目实战(6)- 二次封装Axios

目录 前言新建axiosUtil.js 文件基本配置统一URL.env文件与环境变量示例参考资料 请求头超时时间 request 拦截器response 拦截器统一Api管理测试 前言 在上文中,我们封装了统一的后端数据返回结果,有了标准化的接口数据,我们就可以针对它&a…

[golang 微服务] 2. RPC架构介绍以及通过RPC实现微服务

一.简介 在上一节简单了解了微服务定义和优缺点之后,在使用微服务框架之前,需要首先了解一下RPC架构,通过RPC可以更形象了解微服务的工作流程 RPC的概念 RPC(Remote Procedure Call Protocol),是 远程过程调用的缩写,通俗的说就是…

复合查询.

基本查询 查询工资高于500或岗位为MANAGER的雇员,同时还要满足他们的姓名首字母为大写的J select * from EMP where (sal>500 or jobMANAGER) and ename like J%;按照部门号升序而雇员的工资降序排序 select * from EMP order by deptno, sal desc;使用年薪进…

SpringBoot AOP切面编程 使用案例

参考资料 Springboot AOP实现指定敏感字段数据加密 (数据加密篇 二)【SpringBoot-3】切面AOP实现权限校验:实例演示与注解全解【小家Spring】Spring AOP中Pointcut切入点表达式最全面使用介绍AOP编程过程中的Signature接口 本篇文章核心思想…

C919用了哪些人工智能(AI)技术?

#国产大飞机C919商业首飞#近日,C919在国人的期盼下终于迎来了首次商飞,机票已公开售卖。众所周知,C919是一款全新的、先进的大飞机,那你知道它采用了哪些新的人工智能(AI)技术吗?下面让我来为大…

[Kubernetes] - RabbitMQ学习

1.消息队列 消息: 在应用间传送的数据队列,先进先出 1.2. 作用 好处:解耦, 容错,削峰坏处:降低系统可用性,系统复杂度提高,一致性问题; RabbitMQ组成部分&#xff1a…

4.7 小结

4.7 小结 以上就是局域网的所有知识,我们学习了局域网的基本概念、体系结构、工作原理,根据所采用的技术不同局域网分成了多种类型,包括了IEEE 802.3局域网,令牌环网、令牌总线网、IEEE 802.11无线局域网,我们学习了各…