在JavaScript中深度克隆对象的最有效方法是什么?

克隆JavaScript对象的最有效方法是什么?我见过obj = eval(uneval(o));使用它,但这是非标准的,仅受Firefox支持

我做了类似的事情,obj = JSON.parse(JSON.stringify(o));但对效率提出了质疑。

我还看到了具有各种缺陷的递归复制功能。
我很惊讶没有规范的解决方案存在。

Sam番长逆天2020/03/09 12:28:25

Shallow copy one-liner (ECMAScript 5th edition):

var origin = { foo : {} };
var copy = Object.keys(origin).reduce(function(c,k){c[k]=origin[k];return c;},{});

console.log(origin, copy);
console.log(origin == copy); // false
console.log(origin.foo == copy.foo); // true

And shallow copy one-liner (ECMAScript 6th edition, 2015):

var origin = { foo : {} };
var copy = Object.assign({}, origin);

console.log(origin, copy);
console.log(origin == copy); // false
console.log(origin.foo == copy.foo); // true
逆天2020/03/09 12:28:25
function clone(obj)
 { var clone = {};
   clone.prototype = obj.prototype;
   for (property in obj) clone[property] = obj[property];
   return clone;
 }
樱小小Tom2020/03/09 12:28:25

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...

GIZO-俊宏2020/03/09 12:28:25
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});
西里宝儿Harry2020/03/09 12:28:25

这就是我正在使用的:

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;
}
gia2020/03/09 12:28:24

查看此基准测试:http : //jsben.ch/#/bWfk9

在以前的测试中,速度是最主要的问题,我发现

JSON.parse(JSON.stringify(obj))

是深度克隆对象的最慢方法(它比jQuery.extenddeep标志设置为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的整个过程都非常快。

ES6更新

如果您使用的是Javascript ES6,请尝试使用本机方法进行克隆或浅拷贝。

Object.assign({}, obj);
阿飞神乐2020/03/09 12:28:24

假设您的对象中只有变量,而没有任何函数,则可以使用:

var newObject = JSON.parse(JSON.stringify(oldObject));