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!
_.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.