在JavaScript中深度克隆对象最有效的方法是什么?
克隆JavaScript对象最有效的方法是什么?我见过obj=evalunevalo;正在使用,但是。我做过类似于obj=JSON.parseJSON.stringifyo;但质疑效率。我还看到了具有各种缺陷的递归复制函数。在JavaScript中深度克隆对象最有效的方法是什么?,javascript,object,clone,Javascript,Object,Clone,克隆JavaScript对象最有效的方法是什么?我见过obj=evalunevalo;正在使用,但是。我做过类似于obj=JSON.parseJSON.stringifyo;但质疑效率。我还看到了具有各种缺陷的递归复制函数。 我很惊讶没有标准解决方案存在。如果没有任何内置解决方案,您可以尝试: function clone(obj) { if (obj === null || typeof (obj) !== 'object' || 'isActiveClone' in obj)
我很惊讶没有标准解决方案存在。如果没有任何内置解决方案,您可以尝试:
function clone(obj) {
if (obj === null || typeof (obj) !== 'object' || 'isActiveClone' in obj)
return obj;
if (obj instanceof Date)
var temp = new obj.constructor(); //or new Date(obj);
else
var temp = obj.constructor();
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
obj['isActiveClone'] = null;
temp[key] = clone(obj[key]);
delete obj['isActiveClone'];
}
}
return temp;
}
本地深度克隆
它被称为结构化克隆,在Node11和更高版本中进行实验,有望在浏览器中实现。有关更多详细信息,请参阅
数据丢失的快速克隆-JSON.parse/stringify
如果在对象中不使用日期、函数、未定义、无限、正则表达式、映射、集合、Blob、文件列表、ImageData、稀疏数组、类型化数组或其他复杂类型,则深度克隆对象的非常简单的一行程序是:
JSON.parseJSON.stringifyobject
常数a={
字符串:“字符串”,
电话:123,
布尔:错,
nul:null,
日期:新日期,//字符串化
未定义:未定义,//丢失
inf:Infinity,//强制为“null”
回复://.//,//丢失
}
console.loga;
console.logtypeof a.date;//日期对象
const clone=JSON.parseJSON.stringifya;
console.logclone;
console.logtypeof clone.date;//.toISOString代码的结果:
测试:
这就是我正在使用的:
function cloneObject(obj) {
var clone = {};
for(var i in obj) {
if(typeof(obj[i])=="object" && obj[i] != null)
clone[i] = cloneObject(obj[i]);
else
clone[i] = obj[i];
}
return clone;
}
Crockford建议,我更喜欢使用此函数:
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
var newObject = object(oldObject);
它的简洁,工作如预期,你不需要一个图书馆
编辑:
这是Object.create的多边形填充,因此您也可以使用它
var newObject = Object.create(oldObject);
注意:如果您使用其中一些,您可能会遇到使用hasOwnProperty的某些迭代的问题。因为,创建继承oldObject的新空对象。但它对于克隆对象仍然是有用和实用的
例如,如果oldObject.a=5
但是:
对于类似阵列的对象,似乎还没有理想的深度克隆操作符。正如下面的代码所示,John Resig的jQuery克隆器将具有非数字属性的数组转换为非数组的对象,而RegDwight的JSON克隆器则删除非数字属性。以下测试在多个浏览器上演示了这些要点:
function jQueryClone(obj) {
return jQuery.extend(true, {}, obj)
}
function JSONClone(obj) {
return JSON.parse(JSON.stringify(obj))
}
var arrayLikeObj = [[1, "a", "b"], [2, "b", "a"]];
arrayLikeObj.names = ["m", "n", "o"];
var JSONCopy = JSONClone(arrayLikeObj);
var jQueryCopy = jQueryClone(arrayLikeObj);
alert("Is arrayLikeObj an array instance?" + (arrayLikeObj instanceof Array) +
"\nIs the jQueryClone an array instance? " + (jQueryCopy instanceof Array) +
"\nWhat are the arrayLikeObj names? " + arrayLikeObj.names +
"\nAnd what are the JSONClone names? " + JSONCopy.names)
if (!Object.assign) {
Object.defineProperty(Object, 'assign', {
enumerable: false,
configurable: true,
writable: true,
value: function(target) {
'use strict';
if (target === undefined || target === null) {
throw new TypeError('Cannot convert first argument to object');
}
var to = Object(target);
for (var i = 1; i < arguments.length; i++) {
var nextSource = arguments[i];
if (nextSource === undefined || nextSource === null) {
continue;
}
nextSource = Object(nextSource);
var keysArray = Object.keys(nextSource);
for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
var nextKey = keysArray[nextIndex];
var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
if (desc !== undefined && desc.enumerable) {
to[nextKey] = nextSource[nextKey];
}
}
}
return to;
}
});
}
假设对象中只有变量而没有函数,则可以使用:
var newObject = JSON.parse(JSON.stringify(oldObject));
检查此基准:
在我之前的测试中,我发现速度是一个主要问题
JSON.parse(JSON.stringify(obj))
作为深度克隆对象的最慢方式,它比深度标志设置为true时慢10-20%
当deep标志设置为false shallow clone时,jQuery.extend速度非常快。这是一个很好的选择,因为它包含一些额外的类型验证逻辑,不会复制未定义的属性等,但这也会使您的速度降低一点
如果您知道要克隆的对象的结构,或者可以避免深层嵌套数组,那么您可以在检查hasOwnProperty时在obj循环中编写一个简单的for var i来克隆您的对象,这将比jQuery快得多
最后,如果您试图在热循环中克隆一个已知的对象结构,只需将克隆过程排成一行并手动构建对象,就可以获得更高的性能
JavaScript跟踪引擎在优化循环中的..和检查hasOwnProperty方面很差劲,这也会降低速度。速度绝对必需时手动克隆
var clonedObject = {
knownProp: obj.knownProp,
..
}
注意在日期对象上使用JSON.parseJSON.stringifyobj方法-JSON.stringifynew Date以ISO格式返回日期的字符串表示形式,JSON.parse不会将其转换回日期对象
此外,请注意,至少在Chrome 65中,本机克隆不是一条可行之路。根据JSPerf的说法,通过创建新函数来执行本机克隆比使用JSON.stringify慢近800倍,而JSON.stringify在所有方面都非常快
如果您使用的是Javascript ES6,请尝试此本机方法进行克隆或浅拷贝
Object.assign({}, obj);
这通常不是最有效的解决方案,但它满足了我的需要。下面是简单的测试用例
function clone(obj, clones) {
// Makes a deep copy of 'obj'. Handles cyclic structures by
// tracking cloned obj's in the 'clones' parameter. Functions
// are included, but not cloned. Functions members are cloned.
var new_obj,
already_cloned,
t = typeof obj,
i = 0,
l,
pair;
clones = clones || [];
if (obj === null) {
return obj;
}
if (t === "object" || t === "function") {
// check to see if we've already cloned obj
for (i = 0, l = clones.length; i < l; i++) {
pair = clones[i];
if (pair[0] === obj) {
already_cloned = pair[1];
break;
}
}
if (already_cloned) {
return already_cloned;
} else {
if (t === "object") { // create new object
new_obj = new obj.constructor();
} else { // Just use functions as is
new_obj = obj;
}
clones.push([obj, new_obj]); // keep track of objects we've cloned
for (key in obj) { // clone object members
if (obj.hasOwnProperty(key)) {
new_obj[key] = clone(obj[key], clones);
}
}
}
}
return new_obj || obj;
}
功能测试
f = new Function
f.a = a
ff = clone(f)
ff === f //=> true
ff.a === a //=> false
我知道这是一个老帖子,但我想这可能会对下一个跌跌撞撞的人有所帮助 只要不将对象指定给任何对象,它就不会在内存中保持引用。因此,要创建一个要在其他对象之间共享的对象,必须创建如下工厂:
var a = function(){
return {
father:'zacharias'
};
},
b = a(),
c = a();
c.father = 'johndoe';
alert(b.father);
如果您正在使用它,库中有一个方法
结构化克隆
HTML标准包括可以创建对象深层克隆的。它仍然局限于某些内置类型,但除了JSON支持的少数类型之外,它还支持日期、regexp、映射、集合、blob、文件列表、ImageDatas、稀疏数组、类型化数组,将来可能还会支持更多。它还保留克隆数据中的引用,允许它支持可能导致JSON错误的循环和递归结构
Node.js中的支持:实验性浅拷贝一行:
沙尔
低拷贝一行,2015年:
这里有一个全面的克隆方法,可以克隆任何JavaScript对象。它处理几乎所有的情况:
function clone(src, deep) {
var toString = Object.prototype.toString;
if (!src && typeof src != "object") {
// Any non-object (Boolean, String, Number), null, undefined, NaN
return src;
}
// Honor native/custom clone methods
if (src.clone && toString.call(src.clone) == "[object Function]") {
return src.clone(deep);
}
// DOM elements
if (src.nodeType && toString.call(src.cloneNode) == "[object Function]") {
return src.cloneNode(deep);
}
// Date
if (toString.call(src) == "[object Date]") {
return new Date(src.getTime());
}
// RegExp
if (toString.call(src) == "[object RegExp]") {
return new RegExp(src);
}
// Function
if (toString.call(src) == "[object Function]") {
//Wrap in another method to make sure == is not true;
//Note: Huge performance issue due to closures, comment this :)
return (function(){
src.apply(this, arguments);
});
}
var ret, index;
//Array
if (toString.call(src) == "[object Array]") {
//[].slice(0) would soft clone
ret = src.slice();
if (deep) {
index = ret.length;
while (index--) {
ret[index] = clone(ret[index], true);
}
}
}
//Object
else {
ret = src.constructor ? new src.constructor() : {};
for (var prop in src) {
ret[prop] = deep
? clone(src[prop], true)
: src[prop];
}
}
return ret;
};
有一个,它做得很好。它提供了我所知的最完整的任意对象的递归克隆/复制。它还支持循环引用,这在其他答案中尚未涉及
你也可以。它可以用于浏览器和Node.js
下面是一个关于如何使用它的示例:
安装它与
npm install clone
或者把它包起来
您也可以手动下载源代码
然后您可以在源代码中使用它
var clone = require('clone');
var a = { foo: { bar: 'baz' } }; // inital value of a
var b = clone(a); // clone a -> b
a.foo.bar = 'foo'; // change a
console.log(a); // { foo: { bar: 'foo' } }
console.log(b); // { foo: { bar: 'baz' } }
免责声明:我是该库的作者。这里有一个版本的ConroyP的答案,即使构造函数具有所需的参数,它仍然有效:
//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
object_create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
function deepCopy(obj) {
if(obj == null || typeof(obj) !== 'object'){
return obj;
}
//make sure the returned object has the same prototype as the original
var ret = object_create(obj.constructor.prototype);
for(var key in obj){
ret[key] = deepCopy(obj[key]);
}
return ret;
}
我的库中也提供了此功能
编辑:
感谢Justin McCandless,这是一个更健壮的版本,现在还支持循环引用:
/**
* Deep copy an object (make copies of all its object properties, sub-properties, etc.)
* An improved version of http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
* that doesn't break if the constructor has required parameters
*
* It also borrows some code from http://stackoverflow.com/a/11621004/560114
*/
function deepCopy(src, /* INTERNAL */ _visited, _copiesVisited) {
if(src === null || typeof(src) !== 'object'){
return src;
}
//Honor native/custom clone methods
if(typeof src.clone == 'function'){
return src.clone(true);
}
//Special cases:
//Date
if(src instanceof Date){
return new Date(src.getTime());
}
//RegExp
if(src instanceof RegExp){
return new RegExp(src);
}
//DOM Element
if(src.nodeType && typeof src.cloneNode == 'function'){
return src.cloneNode(true);
}
// Initialize the visited objects arrays if needed.
// This is used to detect cyclic references.
if (_visited === undefined){
_visited = [];
_copiesVisited = [];
}
// Check if this object has already been visited
var i, len = _visited.length;
for (i = 0; i < len; i++) {
// If so, get the copy we already made
if (src === _visited[i]) {
return _copiesVisited[i];
}
}
//Array
if (Object.prototype.toString.call(src) == '[object Array]') {
//[].slice() by itself would soft clone
var ret = src.slice();
//add it to the visited array
_visited.push(src);
_copiesVisited.push(ret);
var i = ret.length;
while (i--) {
ret[i] = deepCopy(ret[i], _visited, _copiesVisited);
}
return ret;
}
//If we've reached here, we have a regular object
//make sure the returned object has the same prototype as the original
var proto = (Object.getPrototypeOf ? Object.getPrototypeOf(src): src.__proto__);
if (!proto) {
proto = src.constructor.prototype; //this line would probably only be reached by very old browsers
}
var dest = object_create(proto);
//add this object to the visited array
_visited.push(src);
_copiesVisited.push(dest);
for (var key in src) {
//Note: this does NOT preserve ES5 property attributes like 'writable', 'enumerable', etc.
//For an example of how this could be modified to do so, see the singleMixin() function
dest[key] = deepCopy(src[key], _visited, _copiesVisited);
}
return dest;
}
//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
object_create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
我有两个很好的答案,这取决于您的目标是否是克隆一个普通的老JavaScript对象 我们还假设您的目的是创建一个完整的克隆,而不返回对源对象的原型引用。如果您对完整的克隆不感兴趣,那么您可以使用Crockford模式中的其他一些答案中提供的许多Object.clone例程 对于普通的旧JavaScript对象,在现代运行时克隆对象的一种行之有效的好方法非常简单:
var clone = JSON.parse(JSON.stringify(obj));
请注意,源对象必须是纯JSON对象。也就是说,它的所有嵌套属性必须是标量,如布尔、字符串、数组、对象等。任何函数或特殊对象(如RegExp或Date)都不会被克隆
效率高吗?见鬼,是的。我们尝试过各种各样的克隆方法,效果最好。我相信一些忍者会想出一个更快的方法。但我怀疑我们谈论的是边际收益
这种方法简单且易于实现。把它包装成一个方便的函数,如果你真的需要挤出一些收益,以后再做
现在,对于非普通JavaScript对象,没有一个真正简单的答案。事实上,这是不可能的,因为JavaScript函数和内部对象状态的动态特性。深度克隆包含函数的JSON结构需要重新创建这些函数及其内部上下文。JavaScript根本没有一种标准化的方法来实现这一点
要做到这一点,正确的方法还是通过一个方便的方法,您可以在代码中声明并重用该方法。方便方法可以赋予您对自己对象的一些理解,因此您可以确保在新对象中正确地重新创建图形
我们自己编写,但这里介绍了我见过的最好的通用方法:
这是正确的想法。作者大卫·沃尔什(David Walsh)对广义函数的克隆进行了评论。根据您的用例,您可能会选择这样做
其主要思想是,您需要专门处理函数或原型类的实例化,也就是说,基于每个类型。这里,他为RegExp和Date提供了一些示例
这段代码不仅简短,而且可读性很强。它很容易扩展
这有效吗?见鬼,是的。如果目标是生成真正的深度复制克隆,那么您必须遍历源对象图的成员。使用这种方法,您可以精确调整要处理的子成员以及如何手动处理自定义类型
好了。两种方法。在我看来,两者都很有效。洛达斯有一个很好的方法:
按性能进行深度复制:
从最好到最差排名
重新分配=字符串数组,数字数组-仅限
切片字符串数组,数字数组-仅限
串联字符串数组,仅数字数组
自定义函数:用于循环或递归复制
jQuery的$.extend
JSON.parse字符串数组、数字数组、对象数组-仅限
s。克隆字符串数组,仅数字数组
Lo Dash的cloneDeep
深度复制一级字符串或数字数组-无引用指针:
当数组包含数字和字符串时-函数如.slice、.concat、.splice、赋值运算符=、下划线.js的克隆函数;将生成数组元素的深度副本
如果重新分配具有最快的性能:
var arr1 = ['a', 'b', 'c'];
var arr2 = arr1;
arr1 = ['a', 'b', 'c'];
并且.slice的性能优于.concat,
深度复制两个或两个以上级别的对象数组-引用指针:
编写自定义函数比$.extend或JSON.parse具有更快的性能:
function copy(o) {
var out, v, key;
out = Array.isArray(o) ? [] : {};
for (key in o) {
v = o[key];
out[key] = (typeof v === "object" && v !== null) ? copy(v) : v;
}
return out;
}
copy(arr1);
使用第三方实用程序功能:
$.extend(true, [], arr1); // Jquery Extend
JSON.parse(arr1);
_.cloneDeep(arr1); // Lo-dash
其中jQuery的$.extend具有更好的性能:
var arr1 = ['a', 'b', 'c'];
var arr2 = arr1;
arr1 = ['a', 'b', 'c'];
下面创建同一对象的两个实例。我找到了它,目前正在使用它。它简单易用
var objToCreate = JSON.parse(JSON.stringify(cloneThis));
只有当您可以使用或
特点:
复制时不会触发getter/setter。
蜜饯盖特
二传手。
保留原型信息。
同时适用于对象文字和功能性写作风格。
代码:
对于希望使用JSON.parseJSON.stringifyobj版本但不丢失日期对象的用户,可以使用将字符串转换回日期: 功能克隆{ var regExp=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/; 返回JSON.parseJSON.stringifyobj,functionk,v{ 如果typeof v==='string'&®Exp.testv 返回新日期 返回v; } } //用法: 原始变量={ a:[1,null,未定义,0,{a:null},新日期], b:{ c{返回0} } } 克隆变量=克隆原始变量 console.logcloned在一行代码中不深度克隆对象的有效方法 方法是ECMAScript 2015 ES6标准的一部分,完全满足您的需要
var clone = Object.assign({}, obj);
Object.assign方法用于将所有可枚举自身属性的值从一个或多个源对象复制到目标对象
polyfill支持较旧的浏览器:
function jQueryClone(obj) {
return jQuery.extend(true, {}, obj)
}
function JSONClone(obj) {
return JSON.parse(JSON.stringify(obj))
}
var arrayLikeObj = [[1, "a", "b"], [2, "b", "a"]];
arrayLikeObj.names = ["m", "n", "o"];
var JSONCopy = JSONClone(arrayLikeObj);
var jQueryCopy = jQueryClone(arrayLikeObj);
alert("Is arrayLikeObj an array instance?" + (arrayLikeObj instanceof Array) +
"\nIs the jQueryClone an array instance? " + (jQueryCopy instanceof Array) +
"\nWhat are the arrayLikeObj names? " + arrayLikeObj.names +
"\nAnd what are the JSONClone names? " + JSONCopy.names)
if (!Object.assign) {
Object.defineProperty(Object, 'assign', {
enumerable: false,
configurable: true,
writable: true,
value: function(target) {
'use strict';
if (target === undefined || target === null) {
throw new TypeError('Cannot convert first argument to object');
}
var to = Object(target);
for (var i = 1; i < arguments.length; i++) {
var nextSource = arguments[i];
if (nextSource === undefined || nextSource === null) {
continue;
}
nextSource = Object(nextSource);
var keysArray = Object.keys(nextSource);
for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
var nextKey = keysArray[nextIndex];
var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
if (desc !== undefined && desc.enumerable) {
to[nextKey] = nextSource[nextKey];
}
}
}
return to;
}
});
}
只是因为我没有看到有人提到,我想人们可能想知道
还提供了一种深度复制对象和数组的方法。AngularJS
如果你用angular,你也可以这么做
var newObject = angular.copy(oldObject);
在JS中克隆对象一直是一个问题,但在ES6之前,我在下面列出了在JavaScript中复制对象的不同方法,假设您拥有下面的对象,并且希望拥有该对象的深度副本:
var obj = {a:1, b:2, c:3, d:4};
在不更改原点的情况下复制此对象的方法很少:
ES5+,使用一个简单的函数为您进行复制:
AngularJs:
jQuery:
下划线JS和Loadash:
希望这些帮助…我回答这个问题已经晚了,但我有另一种克隆对象的方法:
function cloneObject(obj) {
if (obj === null || typeof(obj) !== 'object')
return obj;
var temp = obj.constructor(); // changed
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
obj['isActiveClone'] = null;
temp[key] = cloneObject(obj[key]);
delete obj['isActiveClone'];
}
}
return temp;
}
var b = cloneObject({"a":1,"b":2}); // calling
那么哪一个更好更快呢
var a = {"a":1,"b":2};
var b = JSON.parse(JSON.stringify(a));
及
我已经对代码进行了台架标记,您可以测试结果:
并分享结果:
参考资料:在JavaScript中深度复制对象我认为是最好、最简单的方法
一,。使用JSON.parseJSON.stringifyobject
2.使用创建方法
三,。使用Lo Dash的cloneDeep链接
四,。使用Object.assign方法
但错在什么时候
5.使用underline.js\ux.clone链接
但错在什么时候
JSBEN.CH绩效基准测试1~3
Eval不是邪恶的。使用eval很糟糕。如果你害怕它的副作用,那你就用错了。你担心的副作用是使用它的原因。顺便问一下,有人真的回答了你的问题吗?克隆对象是一件棘手的事情,特别是对于任意集合的自定义对象。这可能是为什么没有现成的方法来做。评估通常是个坏主意,因为。在代码中使用eval可能会导致性能下降。注意,JSON方法可能会丢失任何在JSON中没有等价物的Javascript类型。例如:JSON.parseJSON.stringify{a:null,b:NaN,c:Infinity,d:undefined,e:function{},f:Number,g:false}将生成{a:null,b:null,c:null,g:false}这太错误了!作为在Firefox中实现pushState的人,我对这种黑客行为感到既自豪又厌恶。干得好,伙计们。pushState或Notification hack不适用于某些对象类型,例如Function@ShishirArora你说得对,我刚试过,它抛出了一个“未捕获的DomeException:对象无法克隆”。这对于通知黑客也是如此。它将原语转换为包装器对象,在大多数情况下,这不是一个好的解决方案。@DanubianSailor-我不认为它是……它似乎从一开始就返回原语,而且似乎没有对它们做任何事情,在它们返回时将它们转换为包装器对象。这不是递归复制,因此不能真正解决克隆对象的问题。虽然我测试了一些和u.extend{},obj是目前最快的:例如,它比JSON.parse快20倍,比Object.assign快60%。它可以很好地复制所有子对象。@mwhite克隆和深度克隆之间有区别。这个答案实际上是克隆,但不是深度克隆。问题是关于递归拷贝。Object.assign,以及给定的自定义赋值,不要递归复制,或者它的使用方式可能与jQiery extend相同:angular.extend{},obj@Galvani:应该注意jQuery.extend和angular.extend都是浅拷贝。angular.copy是一个深度复制。这很有趣,但当我运行您的测试时,它实际上告诉我方法1是最慢的一个和我一样,块1是最低的!唯一对我有效的解决方案!必须深度克隆包含具有函数属性的其他对象的对象。很好。为什么要将obj['isActiveClone']=null,然后将其删除?你为什么不叫obj.hasOwnPropertykey?嘿,你的最后一个例子错了。在我看来,对于错误的示例,必须使用_clone而不是_cloneDeep。这创建了方法2。对数组不起作用,对吗?方法
2容易受到原型污染,类似于lodash的DefaultsDep。如果i=='''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''!变量A={b:[{A:[1,2,3],b:[4,5,6],c:[7,8,9]};B=Object.assign{},A;删除B.B[0].B;它还将修改对象A@Gabriel Hautclocq这是因为A.b或b.b都引用内存中的同一对象。如果属性具有非对象值(如数字或字符串),则会正常复制该属性。但是,当复制包含对象值的属性时,它是通过引用而不是通过值进行复制的。另外,请记住数组是JS中的一个对象。证明:typeof[]=='object'&&[]instanceofArray@Unicornist是的,这就是为什么Object.assign没有回答以下问题:在JavaScript中深度克隆对象的最有效方法是什么?。因此,至少不应该将其作为ES6解决方案用于深度克隆。ES6的标题是误导性的,至少应该加以修改,以反映这不是一种深度克隆方法。这个浅薄的词很容易被忽略,很多人只是采用他们在堆栈溢出中找到的最简单的解决方案,而没有阅读所有内容。依赖Object.assign进行对象克隆是危险的。因此我的评论。我使用了一个名为really fast deep clone:的库,对我来说效果非常好。如果您遇到第一条评论中的问题,也将进行浅层复制,您需要启用选项proto:true,对象有属性,而不是变量-函数和日期也不完全是100%克隆注意,您的工作台中有两个错误:首先,它将一些浅克隆lodash u.clone和Object.assign与一些深克隆JSON.parseJSON.stringify进行比较。第二,它说lodash的深度克隆,但它改为浅层克隆;不为我工作。但是Object.assign{},a做了。更糟糕的是,尝试让o={};o、 o=o;克隆BJECTO;我不知道这个处理循环结构感谢jQuery,太好了!
var arr1 = ['a', 'b', 'c']; // Becomes arr1 = ['a', 'b', 'c']
var arr2a = arr1.slice(0); // Becomes arr2a = ['a', 'b', 'c'] - deep copy
var arr2b = arr1.concat(); // Becomes arr2b = ['a', 'b', 'c'] - deep copy
var arr1 = [{object:'a'}, {object:'b'}];
function copy(o) {
var out, v, key;
out = Array.isArray(o) ? [] : {};
for (key in o) {
v = o[key];
out[key] = (typeof v === "object" && v !== null) ? copy(v) : v;
}
return out;
}
copy(arr1);
$.extend(true, [], arr1); // Jquery Extend
JSON.parse(arr1);
_.cloneDeep(arr1); // Lo-dash
var objToCreate = JSON.parse(JSON.stringify(cloneThis));
function clone(target, source){
for(let key in source){
// Use getOwnPropertyDescriptor instead of source[key] to prevent from trigering setter/getter.
let descriptor = Object.getOwnPropertyDescriptor(source, key);
if(descriptor.value instanceof String){
target[key] = new String(descriptor.value);
}
else if(descriptor.value instanceof Array){
target[key] = clone([], descriptor.value);
}
else if(descriptor.value instanceof Object){
let prototype = Reflect.getPrototypeOf(descriptor.value);
let cloneObject = clone({}, descriptor.value);
Reflect.setPrototypeOf(cloneObject, prototype);
target[key] = cloneObject;
}
else {
Object.defineProperty(target, key, descriptor);
}
}
let prototype = Reflect.getPrototypeOf(source);
Reflect.setPrototypeOf(target, prototype);
return target;
}
var clone = Object.assign({}, obj);
if (!Object.assign) {
Object.defineProperty(Object, 'assign', {
enumerable: false,
configurable: true,
writable: true,
value: function(target) {
'use strict';
if (target === undefined || target === null) {
throw new TypeError('Cannot convert first argument to object');
}
var to = Object(target);
for (var i = 1; i < arguments.length; i++) {
var nextSource = arguments[i];
if (nextSource === undefined || nextSource === null) {
continue;
}
nextSource = Object(nextSource);
var keysArray = Object.keys(nextSource);
for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
var nextKey = keysArray[nextIndex];
var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
if (desc !== undefined && desc.enumerable) {
to[nextKey] = nextSource[nextKey];
}
}
}
return to;
}
});
}
var newObject = angular.copy(oldObject);
var obj = {a:1, b:2, c:3, d:4};
function deepCopyObj(obj) {
if (null == obj || "object" != typeof obj) return obj;
if (obj instanceof Date) {
var copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
if (obj instanceof Array) {
var copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = deepCopyObj(obj[i]);
}
return copy;
}
if (obj instanceof Object) {
var copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = deepCopyObj(obj[attr]);
}
return copy;
}
throw new Error("Unable to copy obj this object.");
}
var deepCopyObj = JSON.parse(JSON.stringify(obj));
var deepCopyObj = angular.copy(obj);
var deepCopyObj = jQuery.extend(true, {}, obj);
var deepCopyObj = _.cloneDeep(obj); //latest version UndescoreJs makes shallow copy
function cloneObject(obj) {
if (obj === null || typeof(obj) !== 'object')
return obj;
var temp = obj.constructor(); // changed
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
obj['isActiveClone'] = null;
temp[key] = cloneObject(obj[key]);
delete obj['isActiveClone'];
}
}
return temp;
}
var b = cloneObject({"a":1,"b":2}); // calling
var a = {"a":1,"b":2};
var b = JSON.parse(JSON.stringify(a));
var a = {"a":1,"b":2};
// Deep copy
var newObject = jQuery.extend(true, {}, a);
var obj = {
a: 1,
b: {
c: 2
}
}
var newObj = JSON.parse(JSON.stringify(obj));
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } }
function cloneObject(obj) {
var clone = {};
for(var i in obj) {
if(obj[i] != null && typeof(obj[i])=="object")
clone[i] = cloneObject(obj[i]);
else
clone[i] = obj[i];
}
return clone;
}
var obj = {
a: 1,
b: {
c: 2
}
}
var newObj = cloneObject(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } }
var obj = {
a: 1,
b: {
c: 2
}
}
var newObj = _.cloneDeep(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } }
var obj = {
a: 1,
b: 2
}
var newObj = _.clone(obj);
obj.b = 20;
console.log(obj); // { a: 1, b: 20 }
console.log(newObj); // { a: 1, b: 2 }
var obj = {
a: 1,
b: {
c: 2
}
}
var newObj = Object.assign({}, obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 20 } } --> WRONG
// Note: Properties on the prototype chain and non-enumerable properties cannot be copied.
var obj = {
a: 1,
b: 2
}
var newObj = _.clone(obj);
obj.b = 20;
console.log(obj); // { a: 1, b: 20 }
console.log(newObj); // { a: 1, b: 2 }
var obj = {
a: 1,
b: {
c: 2
}
}
var newObj = _.cloneDeep(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 20 } } --> WRONG
// (Create a shallow-copied clone of the provided plain object. Any nested objects or arrays will be copied by reference, not duplicated.)