It's been said many times but bears repeating: JavaScript is an underappreciated language. Most serious programmers spend time working outside or on the fringes of the world of web development and so don't have a real use for it, while most web developers don't have the theoretical background to appreciate the fact that JavaScript is actually a wonderful language. But with all this Web 2.0 brou-ha-ha it's important to understand the philosophy of JavaScript.

One of the strangest features to programmers who are familar with other object-oriented languages is that JavaScript appears to only support a handful of their features, and those that it does support requires some strange syntax. It's not clear at all whether JavaScript supports any kind of encapsulation or even inheritance! Where, for example, are classes? Scandalous! And yet, all the rumors are true: JavaScript doesn't have a built-in notion of a "class," has no syntax for enabling classical inheritance, and provides no real support for encapsulation.

"Jesse," you might be thinking, "if JavaScript is supposed to be object-oriented but doesn't support these standard, almost universal, features, how can you possibly be calling it a 'wonderful language?'" This critique is unfair. Languages should be judged on their own merits. LISP is not Ruby is not C is not Haskell is not JavaScript. The fact that people even try to level this critique is evidence that most people never try to understand JavaScript qua JavaScript. JavaScript supports all the features of object-orientation, but not through the usual class/instance mechanism. What's more, JavaScript is flexible enough that you can actually add support for the usual notions found in most other object-oriented languages. Let's see how.

Classes, Forms, and George Berkeley

Most object-oriented languages use classical inheritance. You define a hierarchy of abstract classes and instantiate them in the form of objects. For example, you might have a Cat class. An instance of Cat has all the properties held by all cats plus whatever properties are specific to a given cat, e.g., fur color, breed, or the number of toes on each foot. Changing any of these parameters does not make the cat instance any less of a Cat. The philosophically inclined reader might note that this corresponds directly to a realist metaphysics a la Plato or Aristotle. Using Ruby as an example, it would look something like this:

class Cat
    def initialize(name, breed)
        @name = name
        @breed = breed
    end
   
    def speak
        puts "Meow, I'm a #{@breed} cat named #{@name}."
    end
end

persian = Cat.new('Tom', 'Persian')
persian.speak
=> Meow, I'm a Persian cat named Tom.

JavaScript, though, eschews the classical realist school in favor of a hipper, nominalist metaphysics. There is no such thing as a class and everything is really just an instance. Objects inherit directly from other objects and whatever properties they have in common is totally incidental. Code speaks louder than words, so without further adieu

function Cat(name, breed) {
  this.name = name;
  this.breed = breed;
}

Cat.prototype.speak = function() {
    alert("Meow, I am a " + this.breed + " cat named " + this.name + ".");
}
var persian = new Cat('Tom', 'Persian');
persian.speak();

There are three things woth noting. One, JavaScript supports closures. Two, functions are first-order constructs in JavaScript and are used as object constructors. Three, JavaScript uses prototype-based inheritance. For experienced programmers the rarest of the three is definitely the third, so let's focus on that.

Prototype-based inheritance is simple. Every object has a special field called the prototype which points to another object. If an object is asked for a field which it does not directly contain then it looks at the associated object in its prototype field. If that object cannot find the field then it does the same, and so on, until the hierarchy of objects is exhausted or the field is found. This gives the programmer a direct way to establish a hierarchy of objects: we create a Cat object (not class), point every breed of cat's prototype to the Cat object, and then point every specific cat's prototype to a breed's object. Since any object can be modified at will in JavaScript, at each stage the programmer can customize the specific object (e.g., setting persian.breed = 'Persian').

This is the idea behind prototype-based inheritance, but unfortunately JavaScript doesn't support the above mechanism directly, either. The above code, for example, uses the "new" keyword, which seems normal in a language with classes but strange in a prototype-based language. After all, what's the use of a "new" keyword if you're not instantiating any classes?

This is one spot where JavaScript is, in my opinion, inconsistant. Perhaps when people were coming up with the standards that defined JavaScript they thought it would be just too strange to travel so far off the beaten path when everyone was already used to classical inheritance. Using the fact that "new Foo()" returns an object whose prototype is Foo we can write the following1:

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}
Now we have no need for using the function-based constructor syntax and can write our objects directly.
var Cat = {
    speak: function() {
        alert("Meow, I'm a " + this.breed + " cat named " + this.name + ".");
    }
}

var Persian = object(Cat);
Persian.breed = 'Persian';

var Tom = object(Persian);
Tom.name = 'Tom';

Tom.speak();

It wouldn't be hard now to create a generic factory function, which takes as its input a base object and a second object whose fields are used to overwrite fields in the base class, e.g.,

function extend(base, params) {
    var o = object(base);
    for (key in params) {
        o[key] = params[key]
    }
   
    return o;
}
To create 'Tom' we could then do
var Tom = extend(Cat, {breed: 'Persian', name: 'Tom'});

If you're feeling particularly object-oriented the above could be changed to

Object.prototype.extend = function(params) {
    var o = object(this);
    for (key in params) {
        o[key] = params[key]
    }
 
    return o;
}
and then
var Tom = Cat.extend({breed: 'Persian', name: 'Tom'});
Since functions are first-order objects in JavaScript, if a field points to a function, you can then invoke that field as a function, e.g.,
var Tom = Cat.extend({breed: 'Persian', name: 'Tom', dance: function() {alert("I'm dancin'!");});
Tom.dance();

So, there you go, JavaScript nay-sayers. Not only can JavaScript provide for the functionality of other object-oriented languages, but has something to teach us with its own object model. Given the central role JavaScript plays in Web 2.0 it's definitely worth your time to learn these constructs and idioms.


  1. This comes from Douglas Crockford, who, as far as I know, was the first to give an extended exposition on these aspects of JavaScript [back]

4 Comments

  1. BarelyBlogging » Blog Archive » links for 2007-04-02 April 1st, 2007 / 6:30 pm

    […] The Philosophy of JavaScript | 20bits Good article explaining the differences between JavaScript and other object-oriented languages. (tags: javascript) […]

  2. Del May 24th, 2007 / 2:52 am

    Wow, very cool stuff.

    I never really worked with direct objects in javascript and i have seen little code written like the above.

    Thanks!

  3. Bruce October 11th, 2007 / 4:26 pm

    I covered this topic in my Feb, 2007 article: Implementing “Real” Classes in JavaScript
    [see http://www.polyglotinc.com/AJAXscratch/ ] and later extended the technique to handle
    multiple inheritance. A complete AJAX framework was developed using these techniques.

    In learning how JavaScript *really* worked, I at first focused on how to emulate classical
    classes (hence my articles above), but later I started thinking about the possibilities
    opened up by JavaScript’s “class-less” programming. Having started reading Philosophy 101
    books about that time, I realized that while traditional Object Oriented Programming is like
    Plato and Aristotle (as you pointed out), JavaScript can be more like Existentialism.
    I have started working on what that would mean and am recording my thoughts at http://ExistentialProgramming.com/

  4. Matt October 28th, 2007 / 4:26 pm

    Actionscript (as used in Flash) is pretty much the same, I have used almost identical code to create classes in my flash presentations. Some differences, ‘prototype’ becomes ‘__prototype__’ for example. :)
    (What on earth is the above comment about?!)

Leave a Reply