jmnf 7: encapsulation

javascript magic-ninja-foo episode 7: Objects part 4 encapsulation.

We're now going to start to delve a little more deeply into object orientation in javascript. Continuing down the list of of characteristics of object oriented programming languages (described in episode 5), we're going to look at encapsulation and how it can be accomplished in javascript.

In a nutshell, encapsulation means avoiding directly altering the value of instance variables in an object. Isolating the variables has two primary benefits: one it allows you to do boundary checks on values and two, by creating a "gateway" to your object's data, you create an interface you can alter at a later point without disrupting other OO code that uses your object. There are some other implications of encapsulation but they're beyond the scope of this article.

When we wish to access instance variables, we use special methods frequently called 'getters and setters' (or more formally accessors and mutators) to manipulate and inspect the state of the object.

Nothing in the following code snippet should be surprising.

(protip: paste the examples into your broser console to try them out)

/*color setter*/
function setColor(color) {
   this.color = color;
}
/*color getter*/
function getColor() {
   return this.color;
}
/* Constructor function */
function Orange() {
   this.color = "orange";
   this.type = "citrus";
   /*assign the functions as
     methods */
   this.setColor = setColor;
   this.getColor = getColor;
}
/*make an orange object*/
var myOrange = new Orange();
/*set then get, blue oranges?*/
myOrange.setColor("blue");
alert(myOrange.getColor());

We've created a 'color' getter and setter, so in a sense this is a form of encapsulation. You'll notice that we set 'color' to blue in the example. Maybe we have code that operates on the color of oranges (to what end I have no idea) but let's assume a blue orange has the potential to cause serious hiccups in our code (not to mention uncomfortable stares at the blue orange).

We might do a boundary check in the setter method to check the input value. Lets say we only allow green, brown, orange, and mottled colors. We're going to use the dynamic nature of javascript to change the setter method of just the object.

/*reset the color of the object*/
myOrange.setColor("orange");
/* Define a new setter */
function newSetter(color) {
   if( color != "orange" 
     || color != "brown" 
     || color != "green" 
     || color != "mottled" ) {
        alert("no "+color+
              " oranges allowed!");
        return;
        }
   this.color = color;
}
myOrange.setColor = newSetter;
/*try the blue orange again*/
myOrange.setColor("blue");
alert(myOrange.getColor());

This new boundary checking setter keeps us from setting the orange to blue (firing a browser alert to tell us so) and when we check the object we still have an orange orange.

To the veteran OO programmer though, it's obvious that there is a flaw in this object. The color instance variable is still accessible without a method. If we're not disciplined in our use of the getters and setters, we could just as easily modify the instance variable directly.

continuing from above example

myOrange.color = "sparkly";
alert(myOrange.getColor());

We've circumvented the setter by setting the object property directly. Depending on the complexity of your javascript code, this could cause serious headaches.

If we we're writing code in Java, or C++ we would use the 'public' and 'private' keywords to enforce strict encapsulation. They essentially define the external visibility of the members of the object (instance variables and methods). Setting instance variables to private and defining public "getter and setter" methods to manipulate them keeps us from inadvertently creating sparkly oranges.

There's no direct means of specifying access control to data members for objects in javascript, the keywords 'private' and 'public' don't exist. How then can we enforce strict encapsulation? I've heard javascript ninja-masters say that the above code and 'discipline' was the best way to accomplish encapsulation. There are however, a couple of other ways to accomplish stricter encapsulation, which I'll talk about in the next installment.

I've decided to split this article into two. Next, encapsulation part 2, a stricter approach