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

如何正确克隆JavaScript对象?


当前回答

根据Apple JavaScript编码指南:

// Create an inner object with a variable x whose default
// value is 3.
function innerObj()
{
        this.x = 3;
}
innerObj.prototype.clone = function() {
    var temp = new innerObj();
    for (myvar in this) {
        // this object does not contain any objects, so
        // use the lightweight copy code.
        temp[myvar] = this[myvar];
    }
    return temp;
}

// Create an outer object with a variable y whose default
// value is 77.
function outerObj()
{
        // The outer object contains an inner object.  Allocate it here.
        this.inner = new innerObj();
        this.y = 77;
}
outerObj.prototype.clone = function() {
    var temp = new outerObj();
    for (myvar in this) {
        if (this[myvar].clone) {
            // This variable contains an object with a
            // clone operator.  Call it to create a copy.
            temp[myvar] = this[myvar].clone();
        } else {
            // This variable contains a scalar value,
            // a string value, or an object with no
            // clone function.  Assign it directly.
            temp[myvar] = this[myvar];
        }
    }
    return temp;
}

// Allocate an outer object and assign non-default values to variables in
// both the outer and inner objects.
outer = new outerObj;
outer.inner.x = 4;
outer.y = 16;

// Clone the outer object (which, in turn, clones the inner object).
newouter = outer.clone();

// Verify that both values were copied.
alert('inner x is '+newouter.inner.x); // prints 4
alert('y is '+newouter.y); // prints 16

史蒂夫

其他回答

const objClone = { ...obj };

请注意,嵌套对象仍作为引用复制。

您可以使用函数闭包来获得深度复制的所有好处,而无需深度复制。这是一个非常不同的范例,但效果很好。不要试图复制现有对象,只要在需要时使用函数实例化新对象即可。

首先,创建一个返回对象的函数

function template() {
  return {
    values: [1, 2, 3],
    nest: {x: {a: "a", b: "b"}, y: 100}
  };
}

然后创建一个简单的浅层复制函数

function copy(a, b) {
  Object.keys(b).forEach(function(key) {
    a[key] = b[key];
  });
}

创建一个新对象,并将模板的财产复制到其中

var newObject = {}; 
copy(newObject, template());

但上述复制步骤不是必需的。您需要做的就是:

var newObject = template();

现在您有了一个新对象,请测试它的财产:

console.log(Object.keys(newObject));

这将显示:

["values", "nest"]

是的,这些是newObject自己的财产,而不是对另一个对象上财产的引用。让我们检查一下:

console.log(newObject.nest.x.b);

这将显示:

"b"

newObject获得了模板对象的所有财产,但没有任何依赖链。

http://jsbin.com/ISUTIpoC/1/edit?js安慰

我添加此示例是为了鼓励一些讨论,因此请添加一些评论:)

如果你对一个浅拷贝没有问题,underscore.js库有一个克隆方法。

y = _.clone(x);

或者你可以像

copiedObject = _.extend({},originalObject);

A.Levy的答案几乎是完整的,这是我的一点贡献:有一种方法可以处理递归引用,请看下面这行

如果(this[attr]==this)copy[attr]=复制;

如果对象是XMLDOM元素,则必须改用cloneNode

if(this.cloneNode)返回this.clone节点(true);

受A.Levy的详尽研究和Calvin的原型设计方法启发,我提供了以下解决方案:

Object.prototype.clone = function() {
  if(this.cloneNode) return this.cloneNode(true);
  var copy = this instanceof Array ? [] : {};
  for(var attr in this) {
    if(typeof this[attr] == "function" || this[attr]==null || !this[attr].clone)
      copy[attr] = this[attr];
    else if(this[attr]==this) copy[attr] = copy;
    else copy[attr] = this[attr].clone();
  }
  return copy;
}

Date.prototype.clone = function() {
  var copy = new Date();
  copy.setTime(this.getTime());
  return copy;
}

Number.prototype.clone = 
Boolean.prototype.clone =
String.prototype.clone = function() {
  return this;
}

另请参见答案中的Andy Burke注释。

我只是想在本文中添加到所有Object.create解决方案中,这并不能以nodejs所需的方式工作。

在Firefox中

var a = {"test":"test"};
var b = Object.create(a);
console.log(b);´

is

{test:“test”}。

在nodejs中

{}