什么是最有效的方式来克隆一个JavaScript对象?我已经看到obj = eval(uneval(o));被使用,但它是非标准的,仅支持Firefox.我做了事情,如obj = JSON.parse(JSON.stringify(o));但质疑效率。


当前回答

对于一个微小的副本,有一个很好的,简单的方法引入了ECMAScript2018标准,它涉及使用 Spread Operator :

let obj = {a : "foo", b:"bar" , c:10 , d:true , e:[1,2,3] };

let objClone = { ...obj };

我在Chrome浏览器中测试了它,两个对象都存储在不同的位置,所以即时更改儿童值在一个不会改变另一个。

这个技术是非常简单的,直前的,我认为这是一个真正的最佳实践这个问题一次和永远。

其他回答

structuredClone(value)

如有必要,先加载聚合物:

import structuredClone from '@ungap/structured-clone';

查看此答案更多详细信息

如果您不使用日期、功能、未定义、无限、RegExps、地图、集、博布、文件列表、图像数据、分布式列表、类型列表或其它复杂类型在您的对象中,那么一个非常简单的单一列表来深化对象是:

JSON.parse(JSON.stringify(对象) )

lodash - cloneDeep; 可以通过 lodash.clonedeep 模块单独进口,并且可能是您最好的选择,如果您已经不使用图书馆,提供深度克隆功能 AngularJS - angular.copy jQuery - jQuery.extend(真实, { }, oldObject);.clone() 只克隆 DOM 元素仅图书馆 - just-clone; 一部分图书馆的零依赖 npm 模块,只做一件事。

假设您只拥有属性,而不是对象中的任何功能,您只能使用:

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

克罗克福德建议(我更喜欢)使用此功能:

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

var newObject = object(oldObject);

它是干净的,工作如预期,你不需要图书馆。


编辑:

这是一个对 Object.create 的聚合物,所以你也可以使用它。

var newObject = Object.create(oldObject);

注意: 如果你使用其中的一些,你可能有问题与某些 iteration谁使用 hasOwnProperty. 因为,创建创造新的空的对象,继承旧的对象. 但它仍然有用和实用的克隆对象。

例如,如果 oldObject.a = 5;

newObject.a; // is 5

但:

oldObject.hasOwnProperty(a); // is true
newObject.hasOwnProperty(a); // is false

代码:

// extends 'from' object with members from 'to'. If 'to' is null, a deep clone of 'from' is returned
function extend(from, to)
{
    if (from == null || typeof from != "object") return from;
    if (from.constructor != Object && from.constructor != Array) return from;
    if (from.constructor == Date || from.constructor == RegExp || from.constructor == Function ||
        from.constructor == String || from.constructor == Number || from.constructor == Boolean)
        return new from.constructor(from);

    to = to || new from.constructor();

    for (var name in from)
    {
        to[name] = typeof to[name] == "undefined" ? extend(from[name], null) : to[name];
    }

    return to;
}

测试:

var obj =
{
    date: new Date(),
    func: function(q) { return 1 + q; },
    num: 123,
    text: "asdasd",
    array: [1, "asd"],
    regex: new RegExp(/aaa/i),
    subobj:
    {
        num: 234,
        text: "asdsaD"
    }
}

var clone = extend(obj);

这是我创建的最快的方法,不使用原型,所以它将保持在新对象中拥有自己的所有权。

解决方案是对原件的顶级属性进行 iterate,创建两个副本,从原件中删除每个属性,然后重新设置原件并返回新副本,它只需要像顶级属性一样多次 iterate。

唯一的缺点是,原始对象必须配备其原创创建的名称空间,以便重新设置。

copyDeleteAndReset:function(namespace,strObjName){
    var obj = namespace[strObjName],
    objNew = {},objOrig = {};
    for(i in obj){
        if(obj.hasOwnProperty(i)){
            objNew[i] = objOrig[i] = obj[i];
            delete obj[i];
        }
    }
    namespace[strObjName] = objOrig;
    return objNew;
}

var namespace = {};
namespace.objOrig = {
    '0':{
        innerObj:{a:0,b:1,c:2}
    }
}

var objNew = copyDeleteAndReset(namespace,'objOrig');
objNew['0'] = 'NEW VALUE';

console.log(objNew['0']) === 'NEW VALUE';
console.log(namespace.objOrig['0']) === innerObj:{a:0,b:1,c:2};