在JavaScript中,深克隆对象的最有效方法是什么?
克隆JavaScript对象的最有效方法是什么?我已经看过 obj = eval(uneval(o));
被使用,但是非标准,仅由firefox 。
。
我已经完成了 obj = obj = json.parse(json.stringify) (o));
,但质疑效率。
我还看到了具有各种缺陷的递归复制功能。
我很惊讶没有规范的解决方案。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
lodash有一个不错的_。clonedeep(value)方法:
Lodash has a nice _.cloneDeep(value) method:
对于类似阵列的对象,似乎还没有理想的深克隆操作员。如下所示,John Resig的JQuery克隆器将具有非数字属性的数组变成不是数组的对象,RegdWight的JSON Cloner删除了非数字属性。以下测试在多个浏览器上说明了这些点:
There seems to be no ideal deep clone operator yet for array-like objects. As the code below illustrates, John Resig's jQuery cloner turns arrays with non-numeric properties into objects that are not arrays, and RegDwight's JSON cloner drops the non-numeric properties. The following tests illustrate these points on multiple browsers:
( ecmascript第5版)
浅复制单位liner ecmascript 6th Edition 6th Edition 6th Edition 2015,2015,2015,2015年:
Shallow copy one-liner (ECMAScript 5th edition):
And shallow copy one-liner (ECMAScript 6th edition, 2015):
仅仅因为我没有看到 angularjs 提到并认为人们可能想知道...
< a href =“ https://docs.angularjs.org/api/ng/function/angular.copy” rel =“ noreferrer”>
angular.copy.copy
也提供了一种深层的方法复制对象和数组。Just because I didn't see AngularJS mentioned and thought that people might want to know...
angular.copy
also provides a method of deep copying objects and arrays.我有两个好的答案,具体取决于您的目标是克隆“普通的旧JavaScript对象”。
我们还假设您的意图是创建一个完整的克隆,而没有原型引用回到源对象。如果您对完整的克隆不感兴趣,则可以使用其他一些答案(Crockford的模式)中提供的许多object.clone()例程。
对于普通的旧javaScript对象,在现代运行时克隆对象的久经考验的好方法很简单:
请注意,源对象必须是纯JSON对象。这就是说,其所有嵌套属性都必须是标量(例如布尔,字符串,数组,对象等)。任何功能或特殊对象(例如RegexP或日期)都不会克隆。
有效吗?哎呀。我们尝试了各种克隆方法,这最有效。我敢肯定,有些忍者可以使人联想到更快的方法。但是我怀疑我们正在谈论边际收益。
这种方法简单易于实现。将其包裹在便利功能中,如果您确实需要挤出一些收益,请在以后的时间内进行。
现在,对于非平台JavaScript对象,没有一个非常简单的答案。实际上,不可能是因为JavaScript函数和内部对象状态的动态性质。深层克隆具有内部功能的JSON结构需要您重新创建这些功能及其内部上下文。 JavaScript根本没有标准化的方法。
再次执行此操作的正确方法是通过您在代码中声明和重复使用的便利方法。便利方法可以赋予对自己对象的一些了解,因此您可以确保在新对象中正确重新创建图形。
我们写了自己的书,但是我看到的最好的一般方法在这里涵盖:
http://davidwalsh.name /javascript-clone
这是正确的想法。作者(David Walsh)评论了广义功能的克隆。这是您可能选择的,具体取决于您的用例。
主要思想是,您需要特殊处理功能的实例化(可以说是这样说)。在这里,他为Regexp和日期提供了一些示例。
该代码简介不仅是非常可读的。它很容易扩展。
这有效吗?哎呀。鉴于目标是生产一个真正的深拷贝克隆,那么您将不得不走源对象图的成员。使用这种方法,您可以准确调整要治疗的儿童成员以及如何手动处理自定义类型。
所以你去了。两种方法。在我看来,两者都是有效的。
I have two good answers depending on whether your objective is to clone a "plain old JavaScript object" or not.
Let's also assume that your intention is to create a complete clone with no prototype references back to the source object. If you're not interested in a complete clone, then you can use many of the Object.clone() routines provided in some of the other answers (Crockford's pattern).
For plain old JavaScript objects, a tried and true good way to clone an object in modern runtimes is quite simply:
Note that the source object must be a pure JSON object. This is to say, all of its nested properties must be scalars (like boolean, string, array, object, etc). Any functions or special objects like RegExp or Date will not be cloned.
Is it efficient? Heck yes. We've tried all kinds of cloning methods and this works best. I'm sure some ninja could conjure up a faster method. But I suspect we're talking about marginal gains.
This approach is just simple and easy to implement. Wrap it into a convenience function and if you really need to squeeze out some gain, go for at a later time.
Now, for non-plain JavaScript objects, there isn't a really simple answer. In fact, there can't be because of the dynamic nature of JavaScript functions and inner object state. Deep cloning a JSON structure with functions inside requires you recreate those functions and their inner context. And JavaScript simply doesn't have a standardized way of doing that.
The correct way to do this, once again, is via a convenience method that you declare and reuse within your code. The convenience method can be endowed with some understanding of your own objects so you can make sure to properly recreate the graph within the new object.
We're written our own, but the best general approach I've seen is covered here:
http://davidwalsh.name/javascript-clone
This is the right idea. The author (David Walsh) has commented out the cloning of generalized functions. This is something you might choose to do, depending on your use case.
The main idea is that you need to special handle the instantiation of your functions (or prototypal classes, so to speak) on a per-type basis. Here, he's provided a few examples for RegExp and Date.
Not only is this code brief, but it's also very readable. It's pretty easy to extend.
Is this efficient? Heck yes. Given that the goal is to produce a true deep-copy clone, then you're going to have to walk the members of the source object graph. With this approach, you can tweak exactly which child members to treat and how to manually handle custom types.
So there you go. Two approaches. Both are efficient in my view.
我迟到要回答这个问题了,但是我有另一种克隆对象的方法:
那要好得多,更快:
我
已经标记了代码,您可以测试结果在这里:
分享结果:
参考:
I am late to answer this question, but I have an another way of cloning the object:
which is much better and faster then:
and
I have bench-marked the code and you can test the results here:
and sharing the results:

References: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
只有当您可以使用 ecmascript 6 或 transpilers 。
功能:
代码:
Only when you can use ECMAScript 6 or transpilers.
Features:
Code:
这通常不是最有效的解决方案,但它可以实现我需要的。下面的简单测试用例...
循环阵列测试...
功能测试...
This isn't generally the most efficient solution, but it does what I need. Simple test cases below...
Cyclic array test...
Function test...
对于想要使用
JSON.PARSE(JSON.STRINGIFY(OBJ))
版本的人,但不会丢失日期对象,您可以使用parse> parse
methot 的第二个参数回到日期:For the people who want to use the
JSON.parse(JSON.stringify(obj))
version, but without losing the Date objects, you can use the second argument ofparse
method to convert the strings back to Date:我不同意最大的投票的答案在这里。 递归深克隆比 json.parse(json.stringify(obj))的方法快得多。
这是快速参考的功能:
I disagree with the answer with the greatest votes here. A Recursive Deep Clone is much faster than the JSON.parse(JSON.stringify(obj)) approach mentioned.
And here's the function for quick reference:
天然深克隆
现在有一个
structuredclone(value)
) 在所有主要浏览器中支持的功能和node&gt; = 17。它具有 polyfills对于较旧的系统。如果需要,请先加载polyfill:
请参阅this answer for more details, but 注意这些限制:
较旧的答案
与数据丢失快速克隆-JSON.PARSE/Stringify
如果您不使用
date
s,functions,undefined
,infinity
,regexps,地图,集合,斑点,filelists,imagedatas,稀疏数组,键入数组或对象内的其他复杂类型,一个非常简单的一个衬里,可深克隆一个对象是:json.parse(json.stringify(object))< /代码>
请参阅 corban's答案用于基准。
使用库的可靠克隆
由于克隆对象不是微不足道的(复杂类型,循环引用,功能等),因此大多数主要库为克隆对象提供功能。 不要重新发明轮子 - 如果您已经在使用库,请检查其是否具有对象克隆功能。例如,
clonedeep
;可以通过 lodash.clonedeep 模块,并且如果您是您的最佳选择,则可以是您的最佳选择尚未使用提供深克隆功能clone
angular.copy.copy
jquery.extend(true,true,{} )
;.clone()
只有clones dom元素justa克隆
;仅做一件事的零依赖性NPM模块库的一部分。每种场合都有无罪的公用事业。
Native deep cloning
There's now a
structuredClone(value)
function supported in all major browsers and node >= 17. It has polyfills for older systems.If needed, loading the polyfill first:
See this answer for more details, but note these limitations:
Older answers
Fast cloning with data loss - JSON.parse/stringify
If you do not use
Date
s, functions,undefined
,Infinity
, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays or other complex types within your object, a very simple one liner to deep clone an object is:JSON.parse(JSON.stringify(object))
See Corban's answer for benchmarks.
Reliable cloning using a library
Since cloning objects is not trivial (complex types, circular references, function etc.), most major libraries provide function to clone objects. Don't reinvent the wheel - if you're already using a library, check if it has an object cloning function. For example,
cloneDeep
; can be imported separately via the lodash.clonedeep module and is probably your best choice if you're not already using a library that provides a deep cloning functionclone
angular.copy
jQuery.extend(true, { }, oldObject)
;.clone()
only clones DOM elementsjust-clone
; Part of a library of zero-dependency npm modules that do just do one thing.Guilt-free utilities for every occasion.
核对此基准: http://jsben.ch/#/bwfk9
在我以前的测试中,我发现的主要问题
是最慢的克隆对象的最慢方法(比 jquery.extend.extend 带有
deep
标志设置为10-20%的标志)。当
deep
标志设置为false
(浅克隆)时,jquery.extend非常快。这是一个不错的选择,因为它包含一些用于类型验证的额外逻辑,并且不会复制未定义的属性等,但这也会减慢您的速度。如果您知道要克隆的对象的结构,或者可以避免深嵌套数组,则可以为(obj中的var i in obj)编写一个简单的
循环在检查hasownproperty时克隆您的对象,它将是比jQuery快得多。
最后,如果您试图在热循环中克隆已知的对象结构,则可以通过简单地插入克隆过程并手动构造对象来获得更多的性能。
JavaScript Trace引擎在优化
for..in
循环和检查HasownProperty时也会减慢您的速度。当速度是绝对必须的时,手动克隆。当心使用
JSON.PARSE(JSON.STRINGIFY(OBJ))
在日期
对象上的方法 -json.stringify(new Date())
返回ISO格式日期的字符串表示形式,JSON.PARSE()
不转换回date
对象。 a>。此外,请注意,至少在Chrome 65中,本机克隆不是必经之路。根据JSPERF的说法,通过创建新功能来执行本机克隆几乎 800X 慢。使用JSON.Stringify,它在整个台上都非常快。
如果使用JavaScript ES6,请尝试此本机方法进行克隆或浅副本。
Checkout this benchmark: http://jsben.ch/#/bWfk9
In my previous tests where speed was a main concern I found
to be the slowest way to deep clone an object (it is slower than jQuery.extend with
deep
flag set true by 10-20%).jQuery.extend is pretty fast when the
deep
flag is set tofalse
(shallow clone). It is a good option, because it includes some extra logic for type validation and doesn't copy over undefined properties, etc., but this will also slow you down a little.If you know the structure of the objects you are trying to clone or can avoid deep nested arrays you can write a simple
for (var i in obj)
loop to clone your object while checking hasOwnProperty and it will be much much faster than jQuery.Lastly if you are attempting to clone a known object structure in a hot loop you can get MUCH MUCH MORE PERFORMANCE by simply in-lining the clone procedure and manually constructing the object.
JavaScript trace engines suck at optimizing
for..in
loops and checking hasOwnProperty will slow you down as well. Manual clone when speed is an absolute must.Beware using the
JSON.parse(JSON.stringify(obj))
method onDate
objects -JSON.stringify(new Date())
returns a string representation of the date in ISO format, whichJSON.parse()
doesn't convert back to aDate
object. See this answer for more details.Additionally, please note that, in Chrome 65 at least, native cloning is not the way to go. According to JSPerf, performing native cloning by creating a new function is nearly 800x slower than using JSON.stringify which is incredibly fast all the way across the board.
Update for ES6
If you are using Javascript ES6 try this native method for cloning or shallow copy.
结构化的克隆
现代浏览器和运行时间提供A ,暴露html标准的以前的内部结构化克隆/序列化算法用于创建对象的深度克隆。它仍然仅限于某些内置类型,但是除了JSON支持的少数类型外,它支持日期,左右,地图,集合,斑点,斑点,filelists,imagedatas,Imagedatas,稀疏阵列,稀疏阵列,键入阵列,可能会在以后。它还保留了克隆数据中的参考文献,从而使其能够支持会导致JSON错误的周期性和递归结构。
如果您需要支持旧的环境,其余的答案描述了在直接暴露此功能之前使用此功能的解决方法。
同步node.js解决方案:很棒!
Structured Cloning
Modern browsers and runtimes provide a
structuredClone
global function, exposing the HTML standard's previously-internal structured cloning/serialization algorithm for creating deep clones of objects. It's still limited to certain built-in types, but in addition to the few types supported by JSON it supports Dates, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays, and probably more in the future. It also preserves references within the cloned data, allowing it to support cyclical and recursive structures that would cause errors for JSON.In case you need to support older environments, the rest of this answer describes workarounds to use this capability before it was directly exposed.
Synchronous Node.js Workaround: Excellent! ????
Node.js provides a rich interface for the structured serialization API in its
v8
module. Cloning an object is as simple as:Asynchronous Browser Workaround: Usable. ????
The lowest-overhead way to create a structured clone with previous APIs is to post the data through one port of a MessageChannels. The other port will emit a
message
event with a structured clone of the attached.data
. Unfortunately, listening for these events is necessarily asynchronous, and the synchronous alternatives are less practical.Example Use:
Synchronous Browser Workarounds: Awful! ????
There are no good options for creating structured clones synchronously. Here are a couple of impractical hacks instead.
history.pushState()
andhistory.replaceState()
both create a structured clone of their first argument, and assign that value tohistory.state
. You can use this to create a structured clone of any object like this:Example Use:
Though synchronous, this can be extremely slow. It incurs all of the overhead associated with manipulating the browser history. Calling this method repeatedly can cause Chrome to become temporarily unresponsive.
The
Notification
constructor creates a structured clone of its associated data. It also attempts to display a browser notification to the user, but this will silently fail unless you have requested notification permission. In case you have the permission for other purposes, we'll immediately close the notification we've created.Example Use:
假设您只有属性,而对象中没有任何功能,则可以使用:
Assuming that you have only properties and not any functions in your object, you can just use:
如果没有内置的,您可以尝试:
If there wasn't any builtin one, you could try:
克隆(而不是deep-clone)的有效方法在一行代码中的对象
和
object.assign
方法是ecmascript 2015(ES6)标准的一部分,并且确实需要您所需的工作。polyfill 支持较旧的浏览器:
The efficient way to clone(not deep-clone) an object in one line of code
An
Object.assign
method is part of the ECMAScript 2015 (ES6) standard and does exactly what you need.Read more...
The polyfill to support older browsers:
根据表演的深度复制:
根据基准测试
排名从最佳到最差。
https://www.measurethat.net/benchmarks/show/show/17502 /0/deep -copy -comporparison
...
(原始数组 - 仅)slice()
(原始数组 - 仅)(0)
(原始数组 - 仅)concat()
(原始数组 - 仅)json.parse(json.stringify())
数组 - 唯一的)其中:
{}
,array literals[]
深层复制了一系列原始词:
仅具有原始词(即数字,字符串和布尔人),重新分配,
slice(
slice)( )
,concat()
和UnderScore的clone()
可以使用。差异的情况最快:
slice()
的性能比剪接(0)
andconcat()
深复制一系列原始和对象文字:
深复制一个原始,对象文字和原型的数组:
编写自定义功能(比jquery
$。
):或使用第三方实用程序功能:
Deep copy by performance:
Ranked from best to worst, based on benchmarks
https://www.measurethat.net/Benchmarks/Show/17502/0/deep-copy-comparison
...
(primitive arrays - only)slice()
(primitive arrays - only)splice(0)
(primitive arrays - only)concat()
(primitive arrays - only)JSON.parse(JSON.stringify())
(primitive and literal arrays - only)_.cloneDeep()
(any array)$.extend()
(any array)_.clone()
(primitive and literal arrays - only)Where:
{}
, array literals[]
Deep copy an array of primitives:
To deep copy arrays with primitives only (i.e. numbers, strings, and booleans), reassignment,
slice()
,concat()
, and Underscore'sclone()
can be used.Where spread has the fastest performance:
And where
slice()
has better performance thansplice(0)
andconcat()
Deep copy an array of primitive and object literals:
Deep copy an array of primitive, object literals, and prototypes:
Write a custom function (has faster performance than jQuery
$.extend()
):Or use third-party utility functions:
这就是我正在使用的:
This is what I'm using:
代码:
测试:
Code:
Test:
javaScript中的深层复制对象(我认为最好和最简单)
1。使用json.parse(json.stringify(object));
2.创建的方法
3。使用lo-dash的_.clonedeep 链接 lodash
4。使用Object.Assign()方法
,但当
5.使用underscore.js _.clone link link underscore.js
,但当
jsben.ch performance bench performance playgronging 1〜3 http://jsben.ch/kvqld
Deep copying objects in JavaScript (I think the best and the simplest)
1. Using JSON.parse(JSON.stringify(object));
2.Using created method
3. Using Lo-Dash's _.cloneDeep link lodash
4. Using Object.assign() method
BUT WRONG WHEN
5.Using Underscore.js _.clone link Underscore.js
BUT WRONG WHEN
JSBEN.CH Performance Benchmarking Playground 1~3 http://jsben.ch/KVQLd

克隆一个对象在JS中始终是一个关注的问题,但是在ES6之前,我列出了在下面的JavaScript中复制对象的不同方法,请想象您有以下对象,并且想对此进行深刻的副本
:复制此对象的方法,而无需更改原点:
es5+,使用一个简单的函数为您完成副本:
es5+,使用
json.parse
和json.stringify
。角:
jQuery:
inscore.js&amp; lodash:
希望这些帮助…
Cloning an object was always a concern in JS, but it was all about before ES6, I list different ways of copying an object in JavaScript below, imagine you have the Object below and would like to have a deep copy of that:
There are few ways to copy this object, without changing the origin:
ES5+, Using a simple function to do the copy for you:
ES5+, using
JSON.parse
andJSON.stringify
.Angular:
jQuery:
Underscore.js & Lodash:
Hope these help…
有一个 library> library(称为“ clone”),这做得很好。它提供了我所知道的任意对象的最完整的递归克隆/复制。它还支持循环引用,而其他答案还没有涵盖。
您可以在npm 上也找到它。它可用于浏览器和node.js。
这是一个有关如何使用它的示例:
与
ender”> ender 。
您也可以手动下载源代码。
然后,您可以在源代码中使用它。
(免责声明:我是图书馆的作者。)
There’s a library (called “clone”), that does this quite well. It provides the most complete recursive cloning/copying of arbitrary objects that I know of. It also supports circular references, which is not covered by the other answers, yet.
You can find it on npm, too. It can be used for the browser as well as Node.js.
Here is an example on how to use it:
Install it with
or package it with Ender.
You can also download the source code manually.
Then you can use it in your source code.
(Disclaimer: I’m the author of the library.)
我知道这是一个古老的帖子,但我认为这可能对下一个偶然的人有帮助。
只要您不将对象分配给任何内容都没有内存中的参考。因此,要制作要在其他对象之间共享的对象,您必须创建一个工厂:
I know this is an old post, but I thought this may be of some help to the next person who stumbles along.
As long as you don't assign an object to anything it maintains no reference in memory. So to make an object that you want to share among other objects, you'll have to create a factory like so:
如果您正在使用它,则 underscore.js 库具有克隆方法。
If you're using it, the Underscore.js library has a clone method.
这是上面的ConRoyp答案的一个版本,即使构造函数需要参数,也可以使用:
此函数也可以在我的图书馆。
编辑:
这是一个更强大的版本(感谢Justin McCandless,现在也支持循环参考):
Here's a version of ConroyP's answer above that works even if the constructor has required parameters:
This function is also available in my simpleoo library.
Edit:
Here's a more robust version (thanks to Justin McCandless this now supports cyclic references as well):
以下创建了同一对象的两个实例。我找到了它,目前正在使用它。它简单易用。
The following creates two instances of the same object. I found it and am using it currently. It's simple and easy to use.
克罗克福德(Crockford)建议(我更喜欢)使用此功能:
它是简短的,按预期工作,您不需要库。
编辑:
这是
object.create.create
的多填充,因此您也可以使用此功能。注意:如果您使用其中的某些,则可能有一些使用
HasownProperty
的迭代问题。因为,创建
创建新的空对象谁继承了oldobject
。但是它仍然对克隆对象有用且实用。如果
oldobject.a = 5;
but:
Crockford suggests (and I prefer) using this function:
It's terse, works as expected and you don't need a library.
EDIT:
This is a polyfill for
Object.create
, so you also can use this.NOTE: If you use some of this, you may have problems with some iteration who use
hasOwnProperty
. Because,create
create new empty object who inheritsoldObject
. But it is still useful and practical for cloning objects.For exemple if
oldObject.a = 5;
but: