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


当前回答

Lodash 有一个功能,以便你这样做。

var foo = {a: 'a', b: {c:'d', e: {f: 'g'}}};

var bar = _.cloneDeep(foo);
// bar = {a: 'a', b: {c:'d', e: {f: 'g'}}} 

阅读这里的DOC。

其他回答

因为回归只是太昂贵的JavaScript,我发现的大多数答案是使用回归,而JSON方法将错过非JSON转换部分(功能等)。所以我做了一些研究,并发现这个拖拉机技术避免它。

/*
 * Trampoline to avoid recursion in JavaScript, see:
 *     https://www.integralist.co.uk/posts/functional-recursive-javascript-programming/
 */
function trampoline() {
    var func = arguments[0];
    var args = [];
    for (var i = 1; i < arguments.length; i++) {
        args[i - 1] = arguments[i];
    }

    var currentBatch = func.apply(this, args);
    var nextBatch = [];

    while (currentBatch && currentBatch.length > 0) {
        currentBatch.forEach(function(eachFunc) {
            var ret = eachFunc();
            if (ret && ret.length > 0) {
                nextBatch = nextBatch.concat(ret);
            }
        });

        currentBatch = nextBatch;
        nextBatch = [];
    }
};

/*
 *  Deep clone an object using the trampoline technique.
 *
 *  @param target {Object} Object to clone
 *  @return {Object} Cloned object.
 */
function clone(target) {
    if (typeof target !== 'object') {
        return target;
    }
    if (target == null || Object.keys(target).length == 0) {
        return target;
    }

    function _clone(b, a) {
        var nextBatch = [];
        for (var key in b) {
            if (typeof b[key] === 'object' && b[key] !== null) {
                if (b[key] instanceof Array) {
                    a[key] = [];
                }
                else {
                    a[key] = {};
                }
                nextBatch.push(_clone.bind(null, b[key], a[key]));
            }
            else {
                a[key] = b[key];
            }
        }
        return nextBatch;
    };

    var ret = target instanceof Array ? [] : {};
    (trampoline.bind(null, _clone))(target, ret);
    return ret;
};

如果沒有任何內建一個,你可以嘗試:

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

我认为这是最好的解决方案,如果你想通用你的对象克隆算法,它可以用与或没有jQuery,虽然我建议你放弃jQuery的扩展方法,如果你想你克隆的对象有相同的“类”与原始一个。

function clone(obj){
    if(typeof(obj) == 'function')//it's a simple function
        return obj;
    //of it's not an object (but could be an array...even if in javascript arrays are objects)
    if(typeof(obj) !=  'object' || obj.constructor.toString().indexOf('Array')!=-1)
        if(JSON != undefined)//if we have the JSON obj
            try{
                return JSON.parse(JSON.stringify(obj));
            }catch(err){
                return JSON.parse('"'+JSON.stringify(obj)+'"');
            }
        else
            try{
                return eval(uneval(obj));
            }catch(err){
                return eval('"'+uneval(obj)+'"');
            }
    // I used to rely on jQuery for this, but the "extend" function returns
    //an object similar to the one cloned,
    //but that was not an instance (instanceof) of the cloned class
    /*
    if(jQuery != undefined)//if we use the jQuery plugin
        return jQuery.extend(true,{},obj);
    else//we recursivley clone the object
    */
    return (function _clone(obj){
        if(obj == null || typeof(obj) != 'object')
            return obj;
        function temp () {};
        temp.prototype = obj;
        var F = new temp;
        for(var key in obj)
            F[key] = clone(obj[key]);
        return F;
    })(obj);            
}

Lodash 有一个功能,以便你这样做。

var foo = {a: 'a', b: {c:'d', e: {f: 'g'}}};

var bar = _.cloneDeep(foo);
// bar = {a: 'a', b: {c:'d', e: {f: 'g'}}} 

阅读这里的DOC。

下面是我如何深度克隆一个与ES2015默认值和扩展操作器的对象

 const makeDeepCopy = (obj, copy = {}) => {
  for (let item in obj) {
    if (typeof obj[item] === 'object') {
      makeDeepCopy(obj[item], copy)
    }
    if (obj.hasOwnProperty(item)) {
      copy = {
        ...obj
      }
    }
  }
  return copy
}

const testObj = {“类型”:“对象”,“属性”: {“用户Id”: {“类型”:“string”,“机会”:“指南” },“emailAddr”: {“类型”:“string”,“机会”: {“电子邮件”: {“域名”:“fake.com” },“模式”:“+@fake.com” },“需要”: {“用户Id”,“emailAddr” } } const makeDeepCopy = (ob)