25

当您需要在 javascript 中复制对象时,这是关于最佳实践的。

例如:

我有一个对象{ name: 'Dodo', method: function () { console.log(this.name) }}

我需要创建它的副本:

var obj = { name: 'Dodo', method: function () { console.log(this.name) } };
// what is better?
var copyUnderscore = _(obj).clone();
var copySimple = obj;

更好的方法是什么?谢谢!

4

1 回答 1

87

_.clone与赋值完全不同。

_.clone创建一个新对象并将每个值从原始对象复制到新对象。

赋值只是将一个变量指向已经存在的对象。

假设你有一只小狗。我们就叫他雷克斯吧。

如果您正在与某人讨论 Rex,您会称他为 Rex,或者可能是“狗”。这两个都是对有问题的动物的引用。作业类似于为您的宠物使用不同的短语:

rex = {
  type: 'Dog',
  age: '12 Weeks',
  name: "Rex",
  fixed: false,
  fix: function() {
    this.fixed = true;
    console.log(this.name + " Fixed.");
  }
};
theDog = rex;

// Note the use of `===`, which checks for object identity.
// Assignment (as above) is the whole point of `===`
if (theDog === rex) {
   alert("The Dog is the Same as Rex");
}

当您对一个进行更改时,两个引用都会更改。所以假设你“修复”了 Rex:

rex = {
  type: 'Dog',
  age: '12 Weeks',
  name: "Rex",
  fixed: false,
  fix: function() {
    this.fixed = true;
    console.log(this.name + " Fixed.");
  }
};
theDog = rex;
rex.fix();

alert("The Dog is " + (theDog.fixed ? "" : "not ") + "fixed");
alert("Rex is " + (rex.fixed ? "" : "not ") + "fixed");

theDog也是固定的。

现在假设您克隆了 Rex。(为了争论,我们假设他还没有解决)。

rex = {
  type: 'Dog',
  age: '12 Weeks',
  name: "Rex",
  fixed: false,
  fix: function() {
    this.fixed = true;
    console.log(this.name + " Fixed.");
  }
};
theDog = rex;
otherDog = _.clone(rex);

console.log(theDog);
console.log(rex);
console.log(otherDog);

var message = rex === theDog ? "Rex is the same as the dog" : "Rex and the dog are different";
message += "\n";
message += rex === otherDog ? "Rex is the same as the other dog" : "Rex is different from the other dog";
message += "\n";
message += rex.fixed ? "Rex is fixed" : "Rex is not fixed";
message += "\n";
message += otherDog.fixed ? "Other dog is fixed" : "Other dog is not fixed";

alert(message);

otherDog.fix();

message = rex.fixed ? "Rex is fixed" : "Rex is not fixed";
message += "\n";
message += otherDog.fixed ? "Other dog is fixed" : "Other dog is not fixed";
alert(message);
<script src="http://underscorejs.org/underscore-min.js"></script>

中的每个值rex都已复制到otherDog. 奇迹般地,“otherDog”在 12 周大时出生。但修复一个不会修复另一个。

现在因为rextheDog是同一只狗,所以都不是固定的。不过,otherDog 固定的。他是克隆人,不是同一种动物。

有一些微妙之处需要提防。 _.clone不会深度复制。这意味着作为克隆对象中的值的任何对象或数组都通过赋值复制到新对象(请参阅第一个片段以了解其含义)。

这意味着如果rex有一个属性mother是代表他母亲的对象,它将在rex和之间共享otherDog。对 's mother 的任何更改rex都会传播到otherDog. 这与现实生活没有什么不同。生母是一回事。

编辑

作为另一个神奇的注释:克隆一条固定的狗会产生另一条固定的狗。这就是生物学隐喻失效的地方。

再次编辑(2018 年 6 月)

这个问题的读者可能会对另外两个 ES6 功能感兴趣:

对象喷溅

以下与_.clone(副本成员)相同:

let x = {...rex};

对象.assign

以下将成员复制到现有对象,然后返回该对象:

let x = {}; let anotherReferenceToX = Object.assign(x, rex);

奖金!

值得注意的是,lodash 实际上一个深度克隆操作。您也可以使用function (x) { return JSON.parse(JSON.stringify(x)) }. 但这会阻塞循环引用,而 lodash 不会。

于 2013-06-06T12:21:28.057 回答