What's the difference between underscore clone

2019-02-02 23:57发布

问题:

It's about best practices when you need to copy object in javascript..

For example:

I have an object { name: 'Dodo', method: function () { console.log(this.name) }};

I need to create a copy of it:

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

What is the better way? Thanks!

回答1:

_.clone is completely different from assignment.

_.clone creates a new object and copies each value from the original to the new object.

An assignment just points a variable at the object that already exists.

Suppose you had a puppy. Let's call him Rex.

If you're discussing Rex with someone you'll call him Rex, or perhaps "the Dog". Both of those are references to the animal in question. An assignment is analogous to using different phrases for your pet:

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

When you change something about one, it changes for both references. So suppose you "fix" 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 is also fixed.

Now suppose you had Rex cloned. (Let's pretend he's not fixed yet for the sake of argument).

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>

Each value from rex has been copied into otherDog. Miraculously, "otherDog" was born at age 12 weeks. But fixing one will not fix the other.

Now since rex and theDog are the same dog, neither are fixed. However, otherDog is fixed. He is a clone, not the same animal.

There are some subtleties to beware of. _.clone does not copy deeply. This means that any object or array that is a value in the cloned object is copied by assignment to the new object (See the first snippet for a review of what that means).

This means that if rex had a property mother that was an object representing his mother it would be shared between rex and otherDog. Any changes to rex's mother would be propagated to otherDog. This is not that different from real life; the biological mother is one and the same.

EDIT

As another miraculous note: cloning a fixed dog produces another fixed dog. This is where the biological metaphor breaks down.

EDIT AGAIN (June 2018)

There are two additional ES6 pieces of functionality that might be of interest to readers of this question:

Object Splat

The following is the same as _.clone (copies members):

let x = {...rex};

Object.assign

The following copies members to an existing object, and then returns that object:

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

BONUS!

It's worth noting that lodash actually has a deep clone operation. You can also use function (x) { return JSON.parse(JSON.stringify(x)) }. But that will choke on circular references, and lodash will not.