A critical look at javascript’s prototype

Javascript’s prototype is often compared to the inheritance model used by classical OOP languages. In these languages a sub class inherits properties and methods from a super class. In the sub class you can then add and override methods and properties of the super class. Allowing you to create objects with either the generic features of the super class, or the specialized features of the sub class. There is a big difference when using prototype to inherit from an object rather then class.

Inheriting from an object

As javascript doesn’t have classes, prototype let’s one object inherit properties and methods from another object. The difference here is that if you construct a second sub object it will inherit from the same super object. This means that the super object is only instantiated once, and thus both sub objects get their inheritance from the same source. In other words, you now have 3 objects with the same properties, and no way to figure out who is who. This causes the following problem:

function MySuper() {
var counter = 0;
this.count = function () {
return counter++;
}
}

function MySub() {}
MySub.prototype = new MySuper(); // create an instance of MySuper
foo = new MySub();
foo.count() // 1
bar = new MySub();
bar.count() // 2

Public variables to the rescue

In the above example we use the private scope of the constructor MySuper to hide the variable counter. Because both foo and bar inherit from the same object, they are now sharing a variable that they know nothing about. An obvious way around it it to replace the private variable with a public one. However this means that any super object would have to rely completely on public variables to store properties in. Which of course can cause inheriting objects and other parts of the script to misuse properties which are intended to be private. Our solution will then look like this:

function MySuper() {
this._counter = 0;
this.count = function () {
return this._counter++;
}
}
function MySub() {}
MySub.prototype = new MySuper(); // create an instance of MySuper
foo = new MySub();
foo.count() // 1
bar = new MySub();
bar.count() // 1
MySub.prototype._counter //0

The dangers of public variables

Exposing the guts of all your constructors to whoever has access to your objects has a great deal of disadvantages. Anyone using sub objects need to be aware of the variables you’ve created. A common way to indicate that a property shouldn’t be accessed is by using an underscore as the first character of the property name (ie. _counter). This however doesn’t change that anyone extending the code should know that _counter is already used and thus a sub object shouldn’t be using a property of the same name.

This also means that if you’ve created objects that others inherit from, adding a property to your application can break inheriting objects because they might already be using a property by that name. In an environment that’s as uncertain as the browser, where you may never know what scripts are running on a page, the problem get’s even bigger. Any malicious script can access and manipulate all the private data that’s held by your objects. Using a property to store away private date is pretty much the end of secure applications in the browser.

The alternative

Fortunately there is an alternative way of achieving inheritance in javascript, without all the disadvantages of prototype. Prototype is a very powerful tool when used correctly. But it shouldn’t be used to create constructor inheritance in javascript.

In my next article I’ll be introducing something I’ve named the caller extension design pattern. This pattern gives us a way to create constructor inheritance with all the advantages that classical inheritance brings us, but without any of the drawbacks of prototype.

This entry was posted in Javascript and tagged . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>