A fact about javascript objects

11/21/2014 03:03:00 PM
Tweetable
Here's a little fact about javascript: object properties are always mutable.

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:
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";
and again we can output the new property on newObject like so:
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";
In the above, there are actually now three separate objects: a class constructor, which is just a function that creates objects resembling our original myObject variable, as well as two instances of that class, called myObject and newObject, respectively. The instances are truly separate objects, which you can check by verifying that we added property2 only to newObject and not to myObject. So, despite what I said previously, you totally should use classes in javascript. However, this is still a pretty sloppy implementation, because it's pretty cumbersome to create a new instance of a class every time you want to pass an object to a function--there will be times when you want to alter the state of an object before sending it off to a bunch of functions (based on user input, perhaps), but still want to protect the object from any changes performed within those functions. An alternative to this is using the Object.create() method:
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?