Articles

Simulating classes with prototypes in JavaScript

In JavaScript, Object-oriented programming on June 5, 2011 by Matt Giuca

I’ve been programming in JavaScript for years, and have previously vaguely gotten my head around prototypes (what JavaScript has instead of classes), but never fully. I think I have the hang of them now, though, so I thought I’d share some knowledge with you. If you haven’t tried some real object-oriented programming in JavaScript, basically it’s quite different from everything else, because in everything else, you have classes and objects. As we are all taught in OOP 101, objects are instances of classes. So we build classes and then we instantiate them, creating objects.

But JavaScript is a prototype programming language, which means it has no classes, only objects. In prototype languages, objects are instances of other objects. If Object B is an instance of Object A, then Object A is said to be Object B’s prototype. So basically, this sort of unifies the concept if instantiation and inheritance. There is no difference between saying “Foo is an instance of Bar” and “Foo is a subclass of Bar” — in both cases, we say “Foo’s prototype is Bar.”

So that’s all well and good, but there’s one problem: I just want to write code. This is a pretty dismissive attitude, but I think, since we web programmers are forced to use this language, most of us are not really interested in learning a new and rather experimental programming paradigm. We just want to do things “the usual way”. (Note: There is a lot of strong opinion on The Wiki, and I mean the original Wiki and not Wikipedia, regarding prototype programming and why sliced bread does not compare. I personally don’t see the point of conflating objects and classes — to me, it is helpful to distinguish between objects and the types that describe them. That isn’t to say I am against it, just that in this case, I just want to know how to apply my hardened OOP techniques in JavaScript.)

In short, I have written the most basic Python program that uses inheritance. What is the most idiomatic JavaScript equivalent of this code?

class Foo(object):
    def __init__(self, x):              # Constructor
        self.x = x
    def getX(self):
        return self.x

class Bar(Foo):                         # Inherit from Foo
    def __init__(self, x, y):
        super(Bar, self).__init__(x)    # Superclass constructor call
        self.y = y
    def getY(self):
        return self.y

foo = Foo(4)
print(foo.getX())

bar = Bar(2, 9)
print(bar.getX())
print(bar.getY())

If you aren’t versed in Python, the above code simply has a class Foo with a variable x and a getter, getX, and a class Bar which is a subclass of Foo, which introduces a new variable y and a getter, getY. Note that getters aren’t particularly good Python style, but in this case they just serve as examples of methods which operate on the data. Note that Bar’s constructor takes both x and y, and defers the initialisation of x to the superclass constructor. Also note that the instance variables x and y are not private (Python doesn’t have a very good notion of “private members”); I don’t wish to cover encapsulation in this post.

So here’s what I came up with. JavaScript gurus might like to suggest improvements in the comments:

function Foo(x) {                   // Constructor
    this.x = x;
}
Foo.prototype.getX = function() {
    return this.x;
};

function Bar(x, y) {
    Foo.call(this, x);              // Superclass constructor call
    this.y = y;
}
Bar.prototype = new Foo();          // Inherit from Foo
Bar.prototype.getY = function() {
    return this.y;
};

foo = new Foo(4);
print(foo.getX());

bar = new Bar(2, 9);
print(bar.getX());
print(bar.getY());

Let’s break this down. First, we’ll just focus on Foo. You’ll note that I am curiously defining a function, not a class. Yes, to define the JavaScript equivalent of what I think of as a class, you just write its constructor as a top-level function. Note that Foo assigns to “this.x”. The key to what makes this a constructor and not an ordinary function is the way it is called — note the calling syntax uses the “new” keyword. If you call a function in JavaScript with “new“, it creates an object and calls the given function, allowing the function to assign to the new object via “this“. So “new Foo(4)” creates an object “{“x”: 4}”. But what about methods?

Well, since JavaScript is a proper functional programming language, we could have the constructor assign the methods to attributes of the this object, like so:

function Foo(x) {                   // Don't do this!
    this.x = x;
    this.getX = function() {
        return this.x;
    };
}

This is actually a common approach, but I don’t like it. It’s extremely inefficient in terms of space and speed. With this approach, every single object contains a separate getX function, wasting a lot of space. For details, see this Stack Overflow discussion, including some speed tests I ran. We need a solution which lets all instances of Foo share the same method table, like they would in a class-based language (where all instances share a common class).

This is where prototypes come in. In JavaScript, every object has a prototype, which is another object that this object inherits from (think of it like inheritance, but for objects rather than classes). More formally, if an object X has prototype P, if an attempt to look up an attribute of X fails, JavaScript will search for the attribute in P (this can be recursive; a prototype can have a prototype, etc). Therefore, we need to make sure that all “Foo objects” share a prototype, and that that prototype contains all of the “Foo” methods. In the above code, I do this by setting Foo.prototype.getX to a function object.

What’s confusing about this is that Foo.prototype is not the prototype of Foo (the constructor function). It is just an attribute of the function Foo. Foo.prototype is the prototype of any object constructed by Foo. So when I later write “foo = new Foo(4)”, JavaScript does the following:

  1. Create a new object,
  2. Set the new object’s prototype to Foo.prototype,
  3. Call Foo, with the new object as this.
  4. Assign the new object to foo.

Therefore, assigning to attributes of a constructor.prototype makes those attributes available to all objects constructed with that constructor, and they share a value. Commonly, you assign methods here, but you can also assign other values, which will be shared across instances (like static fields in Java, or class variables in Python).

So that’s how Foo works. How about Bar, which requires inheritance? I’ll use the prototype system to simulate class inheritance. The key is the line “Bar.prototype = new Foo().” This creates a new Foo instance (a dummy instance; we won’t actually be using its value, just its prototype), and stores that Foo instance as the “prototype” attribute of Bar — i.e., the prototype of all objects constructed by Bar. We then extend that prototype with a new method, getY. We could also override methods by assigning them to Bar.prototype (not shown here). Note that if we had just said “Bar.prototype = Foo.prototype”, that would be wrong, because adding or overriding methods would also affect any Foo instances. With this approach, Bar.prototype is not equal to Foo.prototype; rather, it is an object whose prototype is Foo.prototype. Therefore, any method lookups which fail on Bar.prototype will fall back to Foo.prototype.

(It sucks that I need to actually call new Foo() to create the dummy Foo object, since it means the constructor must work on undefined inputs. There should be some way to construct “an object with Foo.prototype as its prototype” without directly calling Foo, but I can’t think of one.)

This is easier to visualise with a diagram. Looking at the diagram below, we can see the distinction between constructors with a “prototype” attribute, and prototypes of objects. You can visually trace the lookup of the “getX” method on the “bar” object — “bar” itself has no attribute getX, so we follow the dashed line to its prototype. The prototype (Bar.prototype) has a getY attribute, but no getX attribute, so we follow the dashed line to the prototype’s prototype (Foo.prototype), which has the getX method, so we call that.

Object diagram of the above example

The last thing to note is how the Bar constructor calls its superclass constructor, a very common thing for a subclass constructor to do. I’m using the ‘call’ method, which lets you call a function and explicitly specify the value of “this“. If I just called “Foo(x)”, it would construct a new object and assign to its x attribute, which isn’t what I want. Performing “Foo.call(this, x)” says “call Foo(x), but use the this object from the Bar constructor as the this object in the Foo constructor.” Hence, when Foo assigns to “this.x”, it is assigning to the same this that Bar is constructing.

In summary:

  • When you want to define a “class,” define its constructor as an ordinary function, and have it write to fields of this.
  • Add methods to the “class” by assigning function objects to constructor.prototype.method.
  • Instantiate “classes” by calling the constructor with new.
  • Inherit from another class by assigning new SuperClass() to SubClass.prototype.
  • Call superclass constructors using SuperClass.call(this, args…).

Edit: Added semicolons at the end of “= function” statements.

Advertisements

4 Responses to “Simulating classes with prototypes in JavaScript”

  1. Note: I just found this article which pretty much uses the same approach:
    http://mckoss.com/jscript/object.htm

  2. In order to get a new Foo() without calling its constructor, you can use this method:
    http://www.room51.co.uk/js/beget.html

    (I think it comes from the appropriately short book “Javascript: the good parts” ;))

    I also kinda thought you should be able to set bar.prototype.prototype to Foo, but that doesn’t seem to work at all…

    • Ick! Cheers for the link, but it’s always very annoying when you have to start defining new methods of Object (and checking that they don’t conflict with other ones) to get your job done!

      As for setting bar.prototype.prototype (do you mean Bar.prototype.prototype) — no, you can’t do that. Remember that an object’s “.prototype” attribute is not the same thing as the object’s prototype!

      The diagram above should make it clear — Bar.prototype’s prototype == Foo.prototype. In Firefox and Chrome, you can access an object’s prototype using the “.__proto__” attribute, but this is not part of the ECMAScript language, so I didn’t mention it. But it’s helpful for understanding: what you want to be able to do is set “Bar.prototype.__proto__ = Foo.prototype”, which you can do in Firefox and Chrome to achieve the above inheritance, but you unfortunately can’t do it in portable JavaScript code.

  3. […] I haven’t found much online about the differences, just sites that show you how to accomplish one with the other (such as this: Simulating classes with prototypes in JavaScript) […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: