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


当前回答

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

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)则是克隆,而不是参考。

其他回答

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

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;
}
function clone(obj)
 { var clone = {};
   clone.prototype = obj.prototype;
   for (property in obj) clone[property] = obj[property];
   return clone;
 }

如何在一行代码中克隆(而不是深克隆)对象

Object.assign 方法是 ECMAScript 2015 (ES6) 标准的一部分,并且正是您所需要的。

var clone = Object.assign({}, obj);

使用 Object.assign() 方法将所有可列的属性从一个或多个源对象的值复制到目标对象。

阅读更多...

支持老年浏览器的多元化:

if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

      var to = Object(target);
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }
        nextSource = Object(nextSource);

        var keysArray = Object.keys(nextSource);
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}

这是我的解决方案,没有使用任何图书馆或本地JavaScript功能。

function deepClone(obj) {
  if (typeof obj !== "object") {
    return obj;
  } else {
    let newObj =
      typeof obj === "object" && obj.length !== undefined ? [] : {};
    for (let key in obj) {
      if (key) {
        newObj[key] = deepClone(obj[key]);
      }
    }
    return newObj;
  }
}

在我以前的测试中,速度是我发现的主要担忧。

JSON.parse(JSON.stringify(obj))

是最慢的方式来深化一个对象(它比 jQuery.extend 更慢,深旗定为 10-20% )。

jQuery.extend 是相当快的,当深旗被设置为虚假(shallow clone)。这是一个很好的选择,因为它包含一些额外的逻辑的类型验证,并且不复制未定义的属性,等等,但这也将放缓你下一点。

如果你知道你正在试图克隆的对象的结构,或者可以避免深深的<unk>,你可以写一个简单的为(var i in obj) loop 克隆你的对象,同时检查 hasOwnProperty 它会比 jQuery 快得多。

var clonedObject = {
  knownProp: obj.knownProp,
  ..
}

更新 ES6

Object.assign({}, obj);