<< Previous chapter | Contents | Cover | Next chapter >>

Chapter 8: Object-oriented Programming

In the early nineties, a thing called object-oriented programming stirred up the software industry. Most of the ideas behind it were not really new at the time, but they had finally gained enough momentum to start rolling, to become fashionable. Books were being written, courses given, programming languages developed. All of a sudden, everybody was extolling the virtues of object-orientation, enthusiastically applying it to every problem, convincing themselves they had finally found the right way to write programs.

These things happen a lot. When a process is hard and confusing, people are always on the lookout for a magic solution. When something looking like such a solution presents itself, they are prepared to become devoted followers. For many programmers, even today, object-orientation (or their view of it) is the gospel. When a program is not 'truly object-oriented', whatever that means, it is considered decidedly inferior.

Few fads have managed to stay popular for as long as this one, though. Object-orientation's longevity can largely be explained by the fact that the ideas at its core are very solid and useful. In this chapter, we will discuss these ideas, along with JavaScript's (rather eccentric) take on them. The above paragraphs are by no means meant to discredit these ideas. What I want to do is warn the reader against developing an unhealthy attachment to them.


As the name suggests, object-oriented programming is related to objects. So far, we have used objects as loose aggregations of values, adding and altering their properties whenever we saw fit. In an object-oriented approach, objects are viewed as little worlds of their own, and the outside world may touch them only through a limited and well-defined interface, a number of specific methods and properties. The 'reached list' we used at the end of chapter 7 is an example of this: We used only three functions, makeReachedList, storeReached, and findReached to interact with it. These three functions form an interface for such objects.

The Date, Error, and BinaryHeap objects we have seen also work like this. Instead of providing regular functions for working with the objects, they provide a way to create such objects, using the new keyword, and a number of methods and properties that provide the rest of the interface.


One way to give an object methods is to simply attach function values to it.

var rabbit = {};
rabbit.speak = function(line) {
  print("The rabbit says '", line, "'");
};

rabbit.speak("Well, now you're asking me.");

In most cases, the method will need to know who it should act on. For example, if there are different rabbits, the speak method must indicate which rabbit is speaking. For this purpose, there is a special variable called this, which is always present when a function is called, and which points at the relevant object when the function is called as a method. A function is called as a method when it is looked up as a property, and immediately called, as in object.method().

function speak(line) {
  print("The ", this.adjective, " rabbit says '", line, "'");
}
var whiteRabbit = {adjective: "white", speak: speak};
var fatRabbit = {adjective: "fat", speak: speak};

whiteRabbit.speak("Oh my ears and whiskers, how late it's getting!");
fatRabbit.speak("I could sure use a carrot right now.");

I can now clarify the mysterious first argument to the apply method, for which we always used null in chapter 6. This argument can be used to specify the object that the function must be applied to. For non-method functions, this is irrelevant, hence the null.

speak.apply(fatRabbit, ["Yum."]);

Functions also have a call method, which is similar to apply, but you can give the arguments for the function separately instead of as an array:

speak.call(fatRabbit, "Burp.");

The new keyword provides a convenient way of creating new objects. When a function is called with the word new in front of it, its this variable will point at a new object, which it will automatically return (unless it explicitly returns something else). Functions used to create new objects like this are called constructors. Here is a constructor for rabbits:

function Rabbit(adjective) {
  this.adjective = adjective;
  this.speak = function(line) {
    print("The ", this.adjective, " rabbit says '", line, "'");
  };
}

var killerRabbit = new Rabbit("killer");
killerRabbit.speak("GRAAAAAAAAAH!");

It is a convention, among JavaScript programmers, to start the names of constructors with a capital letter. This makes it easy to distinguish them from other functions.

Why is the new keyword even necessary? After all, we could have simply written this:

function makeRabbit(adjective) {
  return {
    adjective: adjective,
    speak: function(line) {/*etc*/}
  };
}

var blackRabbit = makeRabbit("black");

But that is not entirely the same. new does a few things behind the scenes. For one thing, our killerRabbit has a property called constructor, which points at the Rabbit function that created it. blackRabbit also has such a property, but it points at the Object function.

show(killerRabbit.constructor);
show(blackRabbit.constructor);

Where did the constructor property come from? It is part of the prototype of a rabbit. Prototypes are a powerful, if somewhat confusing, part of the way JavaScript objects work. Every object is based on a prototype, which gives it a set of inherent properties. The simple objects we have used so far are based on the most basic prototype, which is associated with the Object constructor. In fact, typing {} is equivalent to typing new Object().

var simpleObject = {};
show(simpleObject.constructor);
show(simpleObject.toString);

toString is a method that is part of the Object prototype. This means that all simple objects have a toString method, which converts them to a string. Our rabbit objects are based on the prototype associated with the Rabbit constructor. You can use a constructor's prototype property to get access to, well, their prototype:

show(Rabbit.prototype);
show(Rabbit.prototype.constructor);

Every function automatically gets a prototype property, whose constructor property points back at the function. Because the rabbit prototype is itself an object, it is based on the Object prototype, and shares its toString method.

show(killerRabbit.toString == simpleObject.toString);

Even though objects seem to share the properties of their prototype, this sharing is one-way. The properties of the prototype influence the object based on it, but the properties of this object never change the prototype.

The precise rules are this: When looking up the value of a property, JavaScript first looks at the properties that the object itself has. If there is a property that has the name we are looking for, that is the value we get. If there is no such property, it continues searching the prototype of the object, and then the prototype of the prototype, and so on. If no property is found, the value undefined is given. On the other hand, when setting the value of a property, JavaScript never goes to the prototype, but always sets the property in the object itself.

Rabbit.prototype.teeth = "small";
show(killerRabbit.teeth);
killerRabbit.teeth = "long, sharp, and bloody";
show(killerRabbit.teeth);
show(Rabbit.prototype.teeth);

This does mean that the prototype can be used at any time to add new properties and methods to all objects based on it. For example, it might become necessary for our rabbits to dance.

Rabbit.prototype.dance = function() {
  print("The ", this.adjective, " rabbit dances a jig.");
};

killerRabbit.dance();

And, as you might have guessed, the prototypical rabbit is the perfect place for values that all rabbits have in common, such as the speak method. Here is a new approach to the Rabbit constructor:

function Rabbit(adjective) {
  this.adjective = adjective;
}
Rabbit.prototype.speak = function(line) {
  print("The ", this.adjective, " rabbit says '", line, "'");
};

var hazelRabbit = new Rabbit("hazel");
hazelRabbit.speak("Good Frith!");

The fact that all objects have a prototype and receive some properties from this prototype can be tricky. It means that using an object to store a set of things, such as the cats from chapter 4, can go wrong. If, for example, we wondered whether there is a cat called "constructor", we would have checked it like this:

var noCatsAtAll = {};
if ("constructor" in noCatsAtAll)
  print("Yes, there definitely is a cat called 'constructor'.");

This is problematic. A related problem is that it can often be practical to extend the prototypes of standard constructors such as Object and Array with new useful functions. For example, we could give all objects a method called properties, which returns an array with the names of the (non-hidden) properties that the object has:

Object.prototype.properties = function() {
  var result = [];
  for (var property in this)
    result.push(property);
  return result;
};

var test = {x: 10, y: 3};
show(test.properties());

And that immediately shows the problem. Now that the Object prototype has a property called properties, looping over the properties of any object, using for and in, will also give us that shared property, which is generally not what we want. We are interested only in the properties that the object itself has.

Fortunately, there is a way to find out whether a property belongs to the object itself or to one of its prototypes. Unfortunately, it does make looping over the properties of an object a bit clumsier. Every object has a method called hasOwnProperty, which tells us whether the object has a property with a given name. Using this, we could rewrite our properties method like this:

Object.prototype.properties = function() {
  var result = [];
  for (var property in this) {
    if (this.hasOwnProperty(property))
      result.push(property);
  }
  return result;
};

var test = {"Fat Igor": true, "Fireball": true};
show(test.properties());

And of course, we can abstract that into a higher-order function. Note that the action function is called with both the name of the property and the value it has in the object.

function forEachIn(object, action) {
  for (var property in object) {
    if (object.hasOwnProperty(property))
      action(property, object[property]);
  }
}

var chimera = {head: "lion", body: "goat", tail: "snake"};
forEachIn(chimera, function(name, value) {
  print("The ", name, " of a ", value, ".");
});

But, what if we find a cat named hasOwnProperty? (You never know.) It will be stored in the object, and the next time we want to go over the collection of cats, calling object.hasOwnProperty will fail, because that property no longer points at a function value. This can be solved by doing something even uglier:

function forEachIn(object, action) {
  for (var property in object) {
    if (Object.prototype.hasOwnProperty.call(object, property))
      action(property, object[property]);
  }
}

var test = {name: "Mordecai", hasOwnProperty: "Uh-oh"};
forEachIn(test, function(name, value) {
  print("Property ", name, " = ", value);
});

(Note: This example does not currently work correctly in Internet Explorer 8, which apparently has some problems with overriding built-in prototype properties.)

Here, instead of using the method found in the object itself, we get the method from the Object prototype, and then use call to apply it to the right object. Unless someone actually messes with the method in Object.prototype (don't do that), this should work correctly.


hasOwnProperty can also be used in those situations where we have been using the in operator to see whether an object has a specific property. There is one more catch, however. We saw in chapter 4 that some properties, such as toString, are 'hidden', and do not show up when going over properties with for/in. It turns out that browsers in the Gecko family (Firefox, most importantly) give every object a hidden property named __proto__, which points to the prototype of that object. hasOwnProperty will return true for this one, even though the program did not explicitly add it. Having access to the prototype of an object can be very convenient, but making it a property like that was not a very good idea. Still, Firefox is a widely used browser, so when you write a program for the web you have to be careful with this. There is a method propertyIsEnumerable, which returns false for hidden properties, and which can be used to filter out strange things like __proto__. An expression such as this one can be used to reliably work around this:

var object = {foo: "bar"};
show(Object.prototype.hasOwnProperty.call(object, "foo") &&
     Object.prototype.propertyIsEnumerable.call(object, "foo"));

Nice and simple, no? This is one of the not-so-well-designed aspects of JavaScript. Objects play both the role of 'values with methods', for which prototypes work great, and 'sets of properties', for which prototypes only get in the way.


Writing the above expression every time you need to check whether a property is present in an object is unworkable. We could put it into a function, but an even better approach is to write a constructor and a prototype specifically for situations like this, where we want to approach an object as just a set of properties. Because you can use it to look things up by name, we will call it a Dictionary.

function Dictionary(startValues) {
  this.values = startValues || {};
}
Dictionary.prototype.store = function(name, value) {
  this.values[name] = value;
};
Dictionary.prototype.lookup = function(name) {
  return this.values[name];
};
Dictionary.prototype.contains = function(name) {
  return Object.prototype.hasOwnProperty.call(this.values, name) &&
    Object.prototype.propertyIsEnumerable.call(this.values, name);
};
Dictionary.prototype.each = function(action) {
  forEachIn(this.values, action);
};

var colours = new Dictionary({Grover: "blue",
                              Elmo: "orange",
                              Bert: "yellow"});
show(colours.contains("Grover"));
show(colours.contains("constructor"));
colours.each(function(name, colour) {
  print(name, " is ", colour);
});

Now the whole mess related to approaching objects as plain sets of properties has been 'encapsulated' in a convenient interface: one constructor and four methods. Note that the values property of a Dictionary object is not part of this interface, it is an internal detail, and when you are using Dictionary objects you do not need to directly use it.

Whenever you write an interface, it is a good idea to add a comment with a quick sketch of what it does and how it should be used. This way, when someone, possibly yourself three months after you wrote it, wants to work with the interface, they can quickly see how to use it, and do not have to study the whole program.

Most of the time, when you are designing an interface, you will soon find some limitations and problems in whatever you came up with, and change it. To prevent wasting your time, it is advisable to document your interfaces only after they have been used in a few real situations and proven themselves to be practical. ― Of course, this might make it tempting to forget about documentation altogether. Personally, I treat writing documentation as a 'finishing touch' to add to a system. When it feels ready, it is time to write something about it, and to see if it sounds as good in English (or whatever language) as it does in JavaScript (or whatever programming language).


The distinction between the external interface of an object and its internal details is important for two reasons. Firstly, having a small, clearly described interface makes an object easier to use. You only have to keep the interface in mind, and do not have to worry about the rest unless you are changing the object itself.

Secondly, it often turns out to be necessary or practical to change something about the internal implementation of an object type1, to make it more efficient, for example, or to fix some problem. When outside code is accessing every single property and detail in the object, you can not change any of them without also updating a lot of other code. If outside code only uses a small interface, you can do what you want, as long as you do not change the interface.

Some people go very far in this. They will, for example, never include properties in the interface of object, only methods ― if their object type has a length, it will be accessible with the getLength method, not the length property. This way, if they ever want to change their object in such a way that it no longer has a length property, for example because it now has some internal array whose length it must return, they can update the function without changing the interface.

My own take is that in most cases this is not worth it. Adding a getLength method which only contains return this.length; mostly just adds meaningless code, and, in most situations, I consider meaningless code a bigger problem than the risk of having to occasionally change the interface to my objects.


Adding new methods to existing prototypes can be very convenient. Especially the Array and String prototypes in JavaScript could use a few more basic methods. We could, for example, replace forEach and map with methods on arrays, and make the startsWith function we wrote in chapter 4 a method on strings.

However, if your program has to run on the same web-page as another program (either written by you or by someone else) which uses for/in naively ― the way we have been using it so far ― then adding things to prototypes, especially the Object and Array prototype, will definitely break something, because these loops will suddenly start seeing those new properties. For this reason, some people prefer not to touch these prototypes at all. Of course, if you are careful, and you do not expect your code to have to coexist with badly-written code, adding methods to standard prototypes is a perfectly good technique.


In this chapter we are going to build a virtual terrarium, a tank with insects moving around in it. There will be some objects involved (this is, after all, the chapter on object-oriented programming). We will take a rather simple approach, and make the terrarium a two-dimensional grid, like the second map in chapter 7. On this grid there are a number of bugs. When the terrarium is active, all the bugs get a chance to take an action, such as moving, every half second.

Thus, we chop both time and space into units with a fixed size ― squares for space, half seconds for time. This usually makes things easier to model in a program, but of course has the drawback of being wildly inaccurate. Fortunately, this terrarium-simulator is not required to be accurate in any way, so we can get away with it.


A terrarium can be defined with a 'plan', which is an array of strings. We could have used a single string, but because JavaScript strings must stay on a single line it would have been a lot harder to type.

var thePlan =
  ["############################",
   "#      #    #      o      ##",
   "#                          #",
   "#          #####           #",
   "##         #   #    ##     #",
   "###           ##     #     #",
   "#           ###      #     #",
   "#   ####                   #",
   "#   ##       o             #",
   "# o  #         o       ### #",
   "#    #                     #",
   "############################"];

The "#" characters are used to represent the walls of the terrarium (and the ornamental rocks lying in it), the "o"s represent bugs, and the spaces are, as you might have guessed, empty space.

Such a plan-array can be used to create a terrarium-object. This object keeps track of the shape and content of the terrarium, and lets the bugs inside move. It has four methods: Firstly toString, which converts the terrarium back to a string similar to the plan it was based on, so that you can see what is going on inside it. Then there is step, which allows all the bugs in the terrarium to move one step, if they so desire. And finally, there are start and stop, which control whether the terrarium is 'running'. When it is running, step is automatically called every half second, so the bugs keep moving.


Ex. 8.1

The points on the grid will be represented by objects again. In chapter 7 we used three functions, point, addPoints, and samePoint to work with points. This time, we will use a constructor and two methods. Write the constructor Point, which takes two arguments, the x and y coordinates of the point, and produces an object with x and y properties. Give the prototype of this constructor a method add, which takes another point as argument and returns a new point whose x and y are the sum of the x and y of the two given points. Also add a method isEqualTo, which takes a point and returns a boolean indicating whether the this point refers to the same coordinates as the given point.

Apart from the two methods, the x and y properties are also part of the interface of this type of objects: Code which uses point objects may freely retrieve and modify x and y.

function Point(x, y) {
  this.x = x;
  this.y = y;
}
Point.prototype.add = function(other) {
  return new Point(this.x + other.x, this.y + other.y);
};
Point.prototype.isEqualTo = function(other) {
  return this.x == other.x && this.y == other.y;
};

show((new Point(3, 1)).add(new Point(2, 4)));

Make sure your version of add leaves the this point intact and produces a new point object. A method which changes the current point instead would be similar to the += operator, whereas this one is like the + operator.


When writing objects to implement a certain program, it is not always very clear which functionality goes where. Some things are best written as methods of your objects, other things are better expressed as separate functions, and some things are best implemented by adding a new type of object. To keep things clear and organised, it is important to keep the amount of methods and responsibilities that an object type has as small as possible. When an object does too much, it becomes a big mess of functionality, and a formidable source of confusion.

I said above that the terrarium object will be responsible for storing its contents and for letting the bugs inside it move. Firstly, note that it lets them move, it doesn't make them move. The bugs themselves will also be objects, and these objects are responsible for deciding what they want to do. The terrarium merely provides the infrastructure that asks them what to do every half second, and if they decide to move, it makes sure this happens.

Storing the grid on which the content of the terrarium is kept can get quite complex. It has to define some kind of representation, ways to access this representation, a way to initialise the grid from a 'plan' array, a way to write the content of the grid to a string for the toString method, and the movement of the bugs on the grid. It would be nice if part of this could be moved into another object, so that the terrarium object itself doesn't get too big and complex.


Whenever you find yourself about to mix data representation and problem-specific code in one object, it is a good idea to try and put the data representation code into a separate type of object. In this case, we need to represent a grid of values, so I wrote a Grid type, which supports the operations that the terrarium will need.

To store the values on the grid, there are two options. One can use an array of arrays, like this:

var grid = [["0,0", "1,0", "2,0"],
            ["0,1", "1,1", "2,1"]];
show(grid[1][2]);

Or the values can all be put into a single array. In this case, the element at x,y can be found by getting the element at position x + y * width in the array, where width is the width of the grid.

var grid = ["0,0", "1,0", "2,0",
            "0,1", "1,1", "2,1"];
show(grid[2 + 1 * 3]);

I chose the second representation, because it makes it much easier to initialise the array. new Array(x) produces a new array of length x, filled with undefined values.

function Grid(width, height) {
  this.width = width;
  this.height = height;
  this.cells = new Array(width * height);
}
Grid.prototype.valueAt = function(point) {
  return this.cells[point.y * this.width + point.x];
};
Grid.prototype.setValueAt = function(point, value) {
  this.cells[point.y * this.width + point.x] = value;
};
Grid.prototype.isInside = function(point) {
  return point.x >= 0 && point.y >= 0 &&
         point.x < this.width && point.y < this.height;
};
Grid.prototype.moveValue = function(from, to) {
  this.setValueAt(to, this.valueAt(from));
  this.setValueAt(from, undefined);
};

Ex. 8.2

We will also need to go over all the elements of the grid, to find the bugs we need to move, or to convert the whole thing to a string. To make this easy, we can use a higher-order function that takes an action as its argument. Add the method each to the prototype of Grid, which takes a function of two arguments as its argument. It calls this function for every point on the grid, giving it the point object for that point as its first argument, and the value that is on the grid at that point as second argument.

Go over the points starting at 0,0, one row at a time, so that 1,0 is handled before 0,1. This will make it easier to write the toString function of the terrarium later. (Hint: Put a for loop for the x coordinate inside a loop for the y coordinate.)

It is advisable not to muck about in the cells property of the grid object directly, but use valueAt to get at the values. This way, if we decide (for some reason) to use a different method for storing the values, we only have to rewrite valueAt and setValueAt, and the other methods can stay untouched.

Grid.prototype.each = function(action) {
  for (var y = 0; y < this.height; y++) {
    for (var x = 0; x < this.width; x++) {
      var point = new Point(x,


gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.