A fact about javascript objects
Matthew Martin
11/21/2014 03:03:00 PM
Tweetable
Ok, that's not surprising news--javascript objects aren't classes or functions, so there's no information hiding. But also remember that javascript is a dynamically-typed prototype-based language. This interacts with mutability in some surprising ways. Consider the following:
var myObject={
property1:"this is the only property of myObject"
}
This is an object with just one property, called property1 that stores the value "this is the only property of myObject." We can output the value of property1 to the console like so:
property1:"this is the only property of myObject"
}
console.log(myObject.property1);
Now suppose we want a second object that is exactly the same as myObject, except that also has a second property. You could write:
var newObject=myObject;
newObject.property2="property1 is wrong, this object has two properties now";
newObject.property2="property1 is wrong, this object has two properties now";
console.log(newObject.property2);
but here's the thing: we will get the same thing if we try
console.log(myObject.property2);
even though we never added property2 to myObject!This happens because, perhaps surprisingly, we never created a second object. There is only one object in the above code, and it takes on two variable names. newObject is actually nothing more than a memory reference to the original object, and anything done to newObject is applied to the prototype tree of myObject. This has some pretty big implications for how you program in javascript. For example, whenever you pass an object to a junction, anything you do to that object inside the function changes the state of the original object even if you assign it to a local variable!
It's actually fairly hard to override this behavior. One way would be with classes
function ObjectClass(){
this.property1="this is property 1";
}
myObject=new ObjectClass();
newObject=new ObjectClass();
newObject.property2="while new object has two properties, myObject only has one property";
this.property1="this is property 1";
}
myObject=new ObjectClass();
newObject=new ObjectClass();
newObject.property2="while new object has two properties, myObject only has one property";
var newObject=Object.create(myObject);
Now, direct changes to newObject will not alter the state of myObject. But again, this is a pretty sloppy implementation. Object.create(myObject) does not create a new copy of an myObject, but rather creates a new object that inherits from myObject, and myObject remains part of the prototype chain for newObject. This matters for the rest of your program: any change to myObject.property1 will affect newObject, and the method newObject.hasOwnProperty("property1") returns false, because property1 is not local property of newObject.There is no easy way to make a copy of an object in javascript. All other alternatives either miss important properties, duplicate properties, or add properties that don't belong.
None of this is true of most other programming languages. In R, if you pass an object to a function, operations applied to the object passed to the function exist only inside the scope of that function. That is, the program treats the argument in the function as a totally separate copy of the original object. If you want to apply the changes to the original object, you must either rework the function so that the changes are returned and then applied to the original copy, or you must hard-code the object directly inside the function. The latter is bad coding, but the former is usually quite acceptable.
So here's my question? Is this javascript fact a feature or a bug? Is there ever a reason you would want changes applied inside a function to always change the state of the original object? Is there ever a time when you would declare a new variable if you just wanted a reference to an already existing object rather than a separate object?