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

如何正确克隆JavaScript对象?


当前回答

我为这个问题提供了答案,因为我在这里没有看到任何解决DOM元素问题的本地递归实现。

问题是<element>具有父属性和子属性,这些属性链接到具有父值和子值的其他元素,这些元素指向原始<element>,从而导致无限递归或循环冗余。

如果你的目标是安全简单的

{
    '123':456
}

……那么这里的任何其他答案都可能奏效。

但如果你有。。。

{
    '123':<reactJSComponent>,
    '456':document.createElement('div'),
}

…那么你需要这样的东西:

    // cloneVariable() : Clone variable, return null for elements or components.
var cloneVariable = function (args) {
    const variable = args.variable;

    if(variable === null) {
            return null;
    }

    if(typeof(variable) === 'object') {
            if(variable instanceof HTMLElement || variable.nodeType > 0) {
                    return null;
            }

            if(Array.isArray(variable)) {
                    var arrayclone = [];

                    variable.forEach((element) => {
                            arrayclone.push(cloneVariable({'variable':element}));
                    });

                    return arrayclone;
            }

            var objectclone = {};

            Object.keys(variable).forEach((field) => {
                    objectclone[field] = cloneVariable({'variable':variable[field]});
            });

            return objectclone;
    }

    return variable;
}

其他回答

好的,我知道它有很多答案,但没有人指出,EcmaScript5有赋值方法,在FF和Chrome上工作,它复制可枚举的,并且拥有财产和符号。

对象指定(Object Assign)

使用jQuery,可以使用extend进行浅层复制:

var copiedObject = jQuery.extend({}, originalObject)

对copiedObject的后续更改不会影响originalObject,反之亦然。

或制作深度副本:

var copiedObject = jQuery.extend(true, {}, originalObject)

本文来自Brian Huisman的《如何在Javascript中复制数组和对象》:

Object.prototype.clone = function() {
  var newObj = (this instanceof Array) ? [] : {};
  for (var i in this) {
    if (i == 'clone') continue;
    if (this[i] && typeof this[i] == "object") {
      newObj[i] = this[i].clone();
    } else newObj[i] = this[i]
  } return newObj;
};

在ECMAScript 6中有Object.assign方法,它将所有可枚举自身财产的值从一个对象复制到另一个对象。例如:

var x = {myProp: "value"};
var y = Object.assign({}, x); 

但请注意,这是一个浅层复制-嵌套对象仍然作为引用复制。

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注释。