热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JavaScript深拷贝机能剖析

原文:Deep-copyinginJavaScript–DasSur.ma如安在JavaScript中拷贝一个对象?关于这个很简朴的题目,然则答案却不简朴。援用传值在JavaScr

原文:
Deep-copying in Javascript – DasSur.ma

如安在 Javascript 中拷贝一个对象?关于这个很简朴的题目,然则答案却不简朴。

援用传值

在 Javascript 中一切的东西都是援用通报(原文有误,稍后写篇批评文 “By Value” or “By Reference” in Javascript · Issue #22)。

假如你不晓得什么意思,看看下面的例子:

function mutate(obj) {
obj.a = true;
}
const obj = {a: false};
mutate(obj)
console.log(obj.a); // 输出 true

函数 mutate 转变了它的参数。在值通报的场景中,函数的形参只是实参的一个副本——a copy——当函数挪用完成后,并不转变实参。然则在 Javascript 这类援用通报的场景中,函数的形参和实参指向同一个对象,当参数内部转变形参的时刻,函数表面的实参也被转变了。

因而在某些情况下,你须要保留原始对象,这时候你须要把原始对象的一个拷贝传入到函数中,以防备函数转变原始对象。

浅拷贝:Object.assign()

一个简朴的猎取对象拷贝的体式格局是运用 Object.assign(target, sources...)。它吸收恣意数目的源对象,罗列它们的一切属性并分派给target。假如我们运用一个新的空对象target,那末我们就能够完成对象的复制。

const obj = /* ... */;
const copy = Object.assign({}, obj);

但是这只是一个副本。假如我们的对象包含别的对象作为本身的属性,它们将坚持同享援用,这不是我们想要的:

function mutateDeepObject(obj) {
obj.a.thing = true;
}
const obj = {a: {thing: false}};
const copy = Object.assign({}, obj);
mutateDeepObject(copy)
console.log(obj.a.thing); // prints true

Object.assign 要领
只会拷贝源对象本身的而且可罗列的属性到目的对象。该要领运用源对象的
[[Get]]和目的对象的
[[Set]],所以它会挪用相干
getter
setter。因而,它分派属性,而不仅仅是复制或定义新的属性。假如兼并源包含
getter,这能够使其不适合将新属性兼并到原型中。为了将属性定义(包含其可罗列性)复制到原型,应运用
Object.getOwnPropertyDescriptor()
Object.defineProperty()

所以如今怎么办?有几种要领能够建立一个对象的深拷贝。

注重:或许有人提到了对象解构运算,这也是浅拷贝。

JSON.parse

建立对象副本的最陈旧要领之一是:将该对象转换为其 JSON 字符串示意情势,然后将其剖析回对象。这觉得有点压制,但它确切有用:

const obj = /* ... */;
const copy = JSON.parse(JSON.stringify(obj));

这里的瑕玷是你建立一个暂时的,能够很大的字符串,只是为了把它从新放回剖析器。另一个瑕玷是这类要领不能处置惩罚轮回对象。而且轮回对象常常发作。比方,当您构建树状数据结构,个中一个节点援用其父级,而父级又援用其子级。

const x = {};
const y = {x};
x.y = y; // Cycle: x.y.x.y.x.y.x.y.x...
const copy = JSON.parse(JSON.stringify(x)); // throws!

别的,诸如 Map, Set, RegExp, Date, ArrayBuffer 和其他内置范例在举行序列化时会丧失。

Structured Clone 结构化克隆算法

Structured cloning 是一种现有的算法,用于将值从一个处所转移到另一处所。比方,每当您挪用postMessage将音讯发送到另一个窗口或 WebWorker 时,都邑运用它。关于结构化克隆的优点在于它处置惩罚轮回对象并 支撑大批的内置范例。题目是,在编写本文时,该算法并不能直接运用,只能作为其他 API 的一部分。我想我们应当相识一下包含哪些,不是吗。。。

MessageChannel

正如我所说的,只需你挪用postMessage结构化克隆算法就能够运用。我们能够建立一个 MessageChannel 并发送音讯。在吸收端,音讯包含我们原始数据对象的结构化克隆。

function structuralClone(obj) {
return new Promise(resolve => {
const {port1, port2} = new MessageChannel();
port2.Onmessage= ev => resolve(ev.data);
port1.postMessage(obj);
});
}
const obj = /* ... */;
const clOne= await structuralClone(obj);

这类要领的瑕玷是它是异步的。虽然这并没有大碍,然则有时刻你须要运用同步的体式格局来深度拷贝一个对象。

History API

假如你曾运用history.pushState()写过 SPA,你就晓得你能够供应一个状况对象来保留 URL。事实证明,这个状况对象运用结构化克隆 – 而且是同步的。我们必需警惕运用,不要把程序逻辑运用的状况对象搅散了,所以我们须要在完成克隆以后恢复原始状况。为了防备发作任何不测,请运用history.replaceState()而不是history.pushState()

function structuralClone(obj) {
const oldState = history.state;
history.replaceState(obj, document.title);
const copy = history.state;
history.replaceState(oldState, document.title);
return copy;
}
const obj = /* ... */;
const clOne= structuralClone(obj);

但是,仅仅为了复制一个对象,而运用浏览器的引擎,觉得有点太过。别的,Safari 浏览器对replaceState挪用的限定数目为 30 秒内 100 次。

Notification API

在发了一条推文以后,Jeremy Banks 向我展现了第三种要领来应用结构化克隆:Notification API。

function structuralClone(obj) {
return new Notification('', {data: obj, silent: true}).data;
}
const obj = /* ... */;
const clOne= structuralClone(obj);

短小,简约。我喜好它!

然则,它须要浏览器内部的权限机制,所以我疑心它是很慢的。由于某种原因,Safari 老是返回undefined

Performance extravaganza

我想丈量哪一种要领是最高机能的。在我的第一次(无邪的)尝试中,我拿了一个小 JSON 对象,并经由过程差别的体式格局克隆对象 1 千次。荣幸的是,Mathias Bynens 告诉我,当你增加属性到一个对象时,V8有一个缓存。所以我是在给缓存做基准测试。为了确保我永久不会遇到缓存,我编写了一个函数,运用随机密钥称号天生给定深度和宽度的对象,并从新运转测试。

图表!

以下是 Chrome,Firefox 和 Edge 中差别手艺的机能。越低越好。

《Javascript 深拷贝机能剖析》

《Javascript 深拷贝机能剖析》

《Javascript 深拷贝机能剖析》

结论

那末我们从中得到了什么呢?

  • 假如您没有轮回对象,而且不须要保留内置范例,则能够运用跨浏览器的JSON.parse(JSON.stringify())取得最快的克隆机能,这让我觉得异常惊奇。
  • 假如你想要一个恰当的结构化克隆,MessageChannel是你唯一牢靠的跨浏览器的挑选。

假如浏览器平台直接供应一个 structuredClone()函数,会不会更好?我固然如许以为,最新的 HTML 范例正在议论这个 Synchronous clOne= global.structuredClone(value, transfer = []) API · Issue #793 · whatwg/html。


推荐阅读
  • 从零学Java(10)之方法详解,喷打野你真的没我6!
    本文介绍了从零学Java系列中的第10篇文章,详解了Java中的方法。同时讨论了打野过程中喷打野的影响,以及金色打野刀对经济的增加和线上队友经济的影响。指出喷打野会导致线上经济的消减和影响队伍的团结。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • JavaScript设计模式之策略模式(Strategy Pattern)的优势及应用
    本文介绍了JavaScript设计模式之策略模式(Strategy Pattern)的定义和优势,策略模式可以避免代码中的多重判断条件,体现了开放-封闭原则。同时,策略模式的应用可以使系统的算法重复利用,避免复制粘贴。然而,策略模式也会增加策略类的数量,违反最少知识原则,需要了解各种策略类才能更好地应用于业务中。本文还以员工年终奖的计算为例,说明了策略模式的应用场景和实现方式。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
author-avatar
mobiledu2502935431
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有