我有一个对象x。我想将其复制为对象y,这样对y的更改不会修改x。我意识到复制从内置JavaScript对象派生的对象会导致额外的、不需要的财产。这不是问题,因为我正在复制我自己的一个文字构造对象。

如何正确克隆JavaScript对象?


当前回答

老问题的新答案!如果您有幸将ECMAScript 2016(ES6)与Spread Syntax一起使用,这很简单。

keepMeTheSame = {first: "Me!", second: "You!"};
cloned = {...keepMeTheSame}

这为对象的浅层副本提供了一种干净的方法。创建一个深度副本,意味着为每个递归嵌套对象中的每个值创建一个新副本,这需要使用上面更重的解决方案。

JavaScript不断发展。

其他回答

复制最终可能指向自身的对象的问题可以通过简单的检查来解决。每次有复制操作时,添加此复选框。它可能很慢,但应该会起作用。

我使用toType()函数显式返回对象类型。我也有自己的copyObj()函数,它在逻辑上非常相似,可以回答所有三种Object()、Array()和Date()情况。

我在NodeJS中运行它。

尚未测试。

// Returns true, if one of the parent's children is the target.
// This is useful, for avoiding copyObj() through an infinite loop!
function isChild(target, parent) {
  if (toType(parent) == '[object Object]') {
    for (var name in parent) {
      var curProperty = parent[name];

      // Direct child.
      if (curProperty = target) return true;

      // Check if target is a child of this property, and so on, recursively.
      if (toType(curProperty) == '[object Object]' || toType(curProperty) == '[object Array]') {
        if (isChild(target, curProperty)) return true;
      }
    }
  } else if (toType(parent) == '[object Array]') {
    for (var i=0; i < parent.length; i++) {
      var curItem = parent[i];

      // Direct child.
      if (curItem = target) return true;

      // Check if target is a child of this property, and so on, recursively.
      if (toType(curItem) == '[object Object]' || toType(curItem) == '[object Array]') {
        if (isChild(target, curItem)) return true;
      }
    }
  }

  return false;     // Not the target.
}

我不知道这在哪些情况下不起作用,但它给了我一个数组的副本。我觉得它很可爱:)希望它有帮助

copiedArr = origArr.filter(function(x){return true})

好的,假设你有下面的这个对象,你想克隆它:

let obj = {a:1, b:2, c:3}; //ES6

or

var obj = {a:1, b:2, c:3}; //ES5

答案主要取决于您使用的ECMAscript,在ES6+中,您可以简单地使用Object.assign来执行克隆:

let cloned = Object.assign({}, obj); //new {a:1, b:2, c:3};

或使用如下扩展运算符:

let cloned = {...obj}; //new {a:1, b:2, c:3};

但是如果你使用ES5,你可以使用很少的方法,但JSON.stringify,只需确保你没有使用大量数据来复制,但在很多情况下,这可能是一种简单的方法,比如:

let cloned = JSON.parse(JSON.stringify(obj)); 
//new {a:1, b:2, c:3};, can be handy, but avoid using on big chunk of data over and over

我在复制对象时遇到问题。这是因为,当您执行以下操作时,您只对对象进行了“引用”,而当稍后更新源对象值时,克隆的复制对象也会更改值,因为它只是一个“引用”。因此,您可以看到源对象上次更改的多个值。

let x = { a: 1 };
let y = x; // y is a reference to x, so if x changes y also changes and v/v

因此,要解决这个问题,请执行以下操作:

let y = JSON.parse(JSON.stringify(x)); //see Note below

防止引用的另一种方法是执行以下操作:

let x = { a: 1 };
let y = Object.assign({}, x); // Object.assign(target, ...sources)

y.a = 2;
console.log(x); // { a: 1 }
console.log(y); // { a: 2 }

注:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#warning_for_deep_clone

在一行代码中克隆Javascript对象的优雅方法

Object.assign方法是ECMAScript 2015(ES6)标准的一部分,它完全符合您的需要。

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

assign()方法用于将所有可枚举自身财产的值从一个或多个源对象复制到目标对象。

阅读更多。。。

支持旧浏览器的polyfill:

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