克隆JavaScript对象的最有效方法是什么?我见过obj = eval(uneval(o));
使用它,但这是非标准的,仅受Firefox支持。
我做了类似的事情,obj = JSON.parse(JSON.stringify(o));
但对效率提出了质疑。
我还看到了具有各种缺陷的递归复制功能。
我很惊讶没有规范的解决方案存在。
在JavaScript中深度克隆对象的最有效方法是什么?
function clone(obj)
{ var clone = {};
clone.prototype = obj.prototype;
for (property in obj) clone[property] = obj[property];
return clone;
}
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:
var obj = {a:1, b:2, c:3, d:4};
There are few ways to copy this object, without changing the origin:
1) ES5+, Using a simple function to do the copy for you:
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] = cloneSO(obj[i]);
}
return copy;
}
if (obj instanceof Object) {
var copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]);
}
return copy;
}
throw new Error("Unable to copy obj this object.");
}
2) ES5+, using JSON.parse and JSON.stringify.
var deepCopyObj = JSON.parse(JSON.stringify(obj));
3) AngularJs:
var deepCopyObj = angular.copy(obj);
4) jQuery:
var deepCopyObj = jQuery.extend(true, {}, obj);
5) UnderscoreJs & Loadash:
var deepCopyObj = _.cloneDeep(obj); //latest version UndescoreJs makes shallow copy
Hope these help...
var clone = function() {
var newObj = (this instanceof Array) ? [] : {};
for (var i in this) {
if (this[i] && typeof this[i] == "object") {
newObj[i] = this[i].clone();
}
else
{
newObj[i] = this[i];
}
}
return newObj;
};
Object.defineProperty( Object.prototype, "clone", {value: clone, enumerable: false});
这就是我正在使用的:
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;
}
查看此基准测试:http : //jsben.ch/#/bWfk9
在以前的测试中,速度是最主要的问题,我发现
JSON.parse(JSON.stringify(obj))
是深度克隆对象的最慢方法(它比jQuery.extend的deep
标志设置为true 慢10-20%)。
当deep
标志设置为false
(shallow clone)时,jQuery.extend非常快。这是一个很好的选择,因为它包括一些用于类型验证的额外逻辑,并且不会复制未定义的属性等,但这也会使您慢一点。
如果您知道要克隆的对象的结构,或者可以避免使用深层嵌套的数组,则可以for (var i in obj)
在检查hasOwnProperty时编写一个简单的循环来克隆对象,这将比jQuery快得多。
最后,如果您尝试在热循环中克隆已知的对象结构,则只需内联克隆过程并手动构建对象,即可获得更多的性能。
JavaScript跟踪引擎在优化for..in
循环方面很烂,而检查hasOwnProperty也会降低您的速度。绝对必要时,请手动克隆。
var clonedObject = {
knownProp: obj.knownProp,
..
}
当心JSON.parse(JSON.stringify(obj))
在Date
对象上使用方法- JSON.stringify(new Date())
以ISO格式返回日期的字符串表示形式,该格式JSON.parse()
不会转换回Date
对象。有关更多详细信息,请参见此答案。
此外,请注意,至少在Chrome 65中,本机克隆不是可行的方法。根据JSPerf的说法,通过创建新函数执行本机克隆比使用JSON.stringify的速度要快近800倍,而JSON.stringify的整个过程都非常快。
如果您使用的是Javascript ES6,请尝试使用本机方法进行克隆或浅拷贝。
Object.assign({}, obj);
假设您的对象中只有变量,而没有任何函数,则可以使用:
var newObject = JSON.parse(JSON.stringify(oldObject));
Shallow copy one-liner (ECMAScript 5th edition):
And shallow copy one-liner (ECMAScript 6th edition, 2015):