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


当前回答

我迟到回答这个问题,但我有另一种方式来克隆对象:

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);

我已经标记了代码,你可以在这里测试结果:

和分享结果: 参考: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty

其他回答

对于未来的参考,可以使用此代码

第6章:

_clone: function(obj){
    let newObj = {};
    for(let i in obj){
        if(typeof(obj[i]) === 'object' && Object.keys(obj[i]).length){
            newObj[i] = clone(obj[i]);
        } else{
            newObj[i] = obj[i];
        }
    }
    return Object.assign({},newObj);
}

第5章:

function clone(obj){
let newObj = {};
for(let i in obj){
    if(typeof(obj[i]) === 'object' && Object.keys(obj[i]).length){
        newObj[i] = clone(obj[i]);
    } else{
        newObj[i] = obj[i];
    }
}
return Object.assign({},newObj);

) )

E.G

var obj ={a:{b:1,c:3},d:4,e:{f:6}}
var xc = clone(obj);
console.log(obj); //{a:{b:1,c:3},d:4,e:{f:6}}
console.log(xc); //{a:{b:1,c:3},d:4,e:{f:6}}

xc.a.b = 90;
console.log(obj); //{a:{b:1,c:3},d:4,e:{f:6}}
console.log(xc); //{a:{b:90,c:3},d:4,e:{f:6}}

这是我正在使用的:

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;
}

以下是 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;
}

此功能也在我的 simpleoo 图书馆中可用。

编辑:

下面是一个更坚实的版本(感谢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();
    };
}
// obj target object, vals source object
var setVals = function (obj, vals) {
    if (obj && vals) {
        for (var x in vals) {
            if (vals.hasOwnProperty(x)) {
                if (obj[x] && typeof vals[x] === 'object') {
                    obj[x] = setVals(obj[x], vals[x]);
                } else {
                    obj[x] = vals[x];
                }
            }
        }
    }
    return obj;
};

如何将对象的关键与其价值相结合?

function deepClone(o) {
    var keys = Object.keys(o);
    var values = Object.values(o);

    var clone = {};

    keys.forEach(function(key, i) {
        clone[key] = typeof values[i] == 'object' ? Object.create(values[i]) : values[i];
    });

    return clone;
}

注意: 这种方法不一定会做更深的复制,但它只会用一个内部对象的深度复制,这意味着当你给出像 {a: {b: {c: null}}} 这样的东西时,它只会克隆直接在它们内部的对象,所以 deepClone(a.b.c)技术上是对 a.b.c 的参考,而 deepClone(a.b)则是克隆,而不是参考。