Javascript - 如何克隆一个对象?

19
我很困惑。我从myObjOne创建了一个副本,然后我从myObjOne中删除了一个条目,JS也会在我的副本(myObjTwo)中删除该条目?但为什么?
  myObjOne = {};
  myObjOne['name'] = 'xxx';
  myObjOne['id'] = 'yyy';
  myObjOne['plz'] = 'zzz';  

  // clone
  myObjTwo = myObjOne;

  // remove something
  delete myObjOne['name'];

  console.dir(myObjTwo);

例子 http://jsbin.com/itixes/edit#javascript,html


1
请看这个问题 - Ranhiru Jude Cooray
2
可能是在Javascript中复制对象的重复问题。 - Matt
8个回答

24

更新:根据评论中所示,将 Object.create 从克隆方法中移除。

  myObjTwo = myObjOne;

不进行克隆,而只是复制引用。

如果您想要克隆,您可以使用JSON.parseJSON.stringify

var x = {a:{b:{c:{'d':'e'}}}};
var y = JSON.parse(JSON.stringify(x));  //y is a clone of x
console.log(y.a.b.c.d); //prints e
console.log(y === x); //prints false

警告:正如Raynos在评论中提到的,这个基于JSON的克隆方案不会在输出对象中保留输入对象的方法。如果您的对象不包含任何方法,则此解决方案已足够好。方法是对象的属性,它们是函数。如果var obj = {add: function(a, b) {return a+b;}},那么addobj的一个方法。

如果您需要支持方法复制的解决方案,请参考以下SO答案(由musefan、Matt和Ranhiru Cooray指出):

我建议看看如何正确地克隆JavaScript对象?


a={name:1};b=Object.create(a);delete a.name;现在b也没有'name'属性了。 - spicavigo
Object.create 不会创建一个克隆,而是将 x 添加到 y 的原型链中。 - pimvdb
@pimvdb,spicavigo感谢指出。已经移除了Object.create - Narendra Yadala
2
使用JSON进行克隆非常昂贵,会破坏方法。 - Raynos
1
@Raynos 如果您希望包括更快的方法,请随意更新我的答案。我认为对于简单的对象,它已经足够快和简洁了。在发布之前,我还检查了jsperf http://jsperf.com/clone/2,看起来相当可比。无论如何,请随意更新。 - Narendra Yadala
@Narendra,浅层次的按属性复制非常简单。而深度复制则是一场噩梦。JSON是一个明智的解决方案,你只是忘记提及它的局限性了。 - Raynos

16

你可以这样使用jQuery:

var myObjTwo = jQuery.extend(true, {}, myObjOne);

第一个参数表明我们想要对myObjOne进行深拷贝。


4

这并不是clone(克隆)的正确方法,这只是将同一个原始对象存储在另一个变量中。也许这个答案可以帮助您。


2

有很多关于如何复制对象及其属性以及所有被其属性引用的对象的建议。以下是一个版本,它克隆对象而不是复制它,并使得克隆体继承后来添加的所有属性,除了被克隆体自身属性所隐藏的那些属性:

var cloneOf = (function() {
  function F(){}
  return function(o) {
    F.prototype = o;
    return new F();
  }
}());

有些人可能会认出这个模式。一个例子:

var base = {foo:'foo', bar:'bar'};
var baseClone = cloneOf(base);
alert(baseClone.foo);  // foo

为什么你会使用原型链,而不是复制属性? - Raynos
因为这是“克隆”对象的一种方式 - OP没有说克隆应该具有什么期望,所以任何事情都可以。 - RobG
这个功能非常好用。它可以处理具有多个嵌套对象/子元素和函数的对象。在克隆对象之后,您可以删除“原始”对象,而克隆对象将保持完好无损。 - Jakob Sternberg

2
使用ES6,使用扩展运算符。
myObjTwo = {...myObjOne}

es6中的扩展运算符只是一个省略号。它会创建原始数据的副本,即使原始数据已被销毁。

1

0

简单。

var clone=function(o){
      var n= {}.toString.apply(o)=="[object Array]" ? []:{};
      for(i in o)
         n[i]= typeof o[i]=='object' ? clone(o[i]):o[i];
      return n;
 };

使用方法:

var x={a:{d:34},b:33};
var y=clone(x);  // clones 'x'

0

你的代码行 myObjTwo = myObjOne 并没有克隆 myObjOne,它只是创建了一个指向同一对象的重复引用!

实际上,正确的方法是使用克隆函数,比如从 underscore.js 这样的库中获取。但是,看起来你需要阅读和学习一下 Javascript 中对象和指针的概念。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接