Oh Javascript, you sneaky bastard.
Let's say you have an array of objects:
var arr = [{}, {}, {}]
Can you use Array.prototype.slice() on them?
MDN defines .slice() as
"...(a) method returns a shallow copy of a portion of an array into a new array object."
So yes, in theory, you can...but be careful.
Javascript has some really subtle "gotchas" when it comes to objects, which can make debugging difficult.
Let's back-track and talk about pass-by-reference and pass-by-value in Javascript, because there's an important difference between the two, which can send you down a sad hole of slight annoyance.
In JS, primitive data types (string, number, etc.) are passed-by-value. This means that variables point to specific values, not references.
var x = 1;
var y = x;
console.log(y) //--> 1
x = 2;
console.log(y) //--> 1
console.log(x) //--> 2
When we declare that y = x, we are setting y equal to 1. y does not point to x, it points to x's value of 1. So when we change the value of x to 2, y continues being 1, because we have not changed y.
Objects, however, dance to their own tune. They can be both pass-by-value AND pass-by-reference. It depends on the situation.
Let's play around with two objects: obj1 and obj2. We'll have a reference variable to keep track of things.
var status = {hello: 'unchanged'}
var obj1 = {}, obj2 = {};
We will have them both refer to status
.
obj1.x = status;
obj2.x = status;
console.log(obj1.x) //--> Object {hello: 'unchanged'}
console.log(obj2.x) //--> Object {hello: 'unchanged'}
That should be obvious right?
We know that whatever we changed obj1 to, it won't affect obj2.
obj1 = {x: {status: 'changed'}};
console.log(obj1.x) //--> Object {hello: 'changed'}
console.log(obj2.x) //--> Object {hello: 'unchanged'}
If you're lost at this point, this post is not for you.
But what if you changed obj1.x.hello?
status = {hello: 'unchanged'};
obj1 = {}; obj2 = {};
obj1.x = status;
obj2.x = status;
obj1.x.hello = 'changed';
What are obj1.x and obj2.x now? :)
And here we see these same principles being applied in closures.
function createObj(ref) {
return function() {
return {
x: ref
}
};
}
var functionFactory = createObj({hello: 'unchanged'});
var obj3 = functionFactory(), obj4 = functionFactory();
console.log(obj3.x) //--> Object {hello: 'unchanged'}
console.log(obj4.x) //--> Object {hello: 'unchanged'}
But what about...
obj1 = {
x: obj4.x
};
obj1.x.status = 'changed';
console.log(obj3.x)
console.log(obj4.x)
What would we console log?
Wee!
The deepcopy library from npm has been quite useful in helping get around this mess.