In this post we present the Proto API which implements inheritance in JavaScript in a purely prototypal fashion. This contrasts it with all other JavaScript inheritance APIs that the author is aware of.
To clarify what “purely prototypal” means, let us look at class inheritance and prototypal inheritance and how it compares to JavaScript:
To improve JavaScript’s inheritance, most frameworks go the route of class inheritance and introduce class objects. For example, the following is Qooxdoo code:
qx.Class.define("twitter.MainWindow", { extend : qx.ui.window.Window, construct : function() { this.base(arguments, "twitter") } });Instead of introducing classes as a new mechanism, the Proto API presented in this post is purely prototypal. As a running example, the following code uses the API to create an initial person.
var person0 = Proto.extendWith({ describe: function() { return "Person called "+this.name; } }, { name: "" });person0 has a property name and a method describe(). The created prototype chain starts with the actual instance containing the property, continues with the prototype containing the method and ends with the proto-prototype which provides all the API functionality (such as extendWith()). Workers extend persons: they have a title and their describe method works differently. Accordingly, the initial worker instance worker0 builds on person0.
var worker0 = person0.extendProto({ describe: function($super) { return $super() + " (" + this.title + ")"; } }, { title: "" });extendProto() extends both the prototype of person0 and the object itself. To do so, the prototype of person0 becomes the prototype of the first argument which in turn becomes the prototype of a new copy of person0. The second argument is then appended to this new copy (because here, we don’t have the option of a reference in JavaScript).
worker0 extends person0 by copying and adding to it. ProtoWorker extends ProtoPerson by pointing to it. |
var person0 = Proto.extendWith({ init: function(name) { this.name = name; }, ... var worker0 = person0.extendProto({ init: function($super, name, title) { $super(name); this.title = title; }, ...Interaction:
> var john = person0.copy("john"); > john.describe() Person called john > var jane = worker0.copy("jane", "manager"); > jane.describe() Person called jane (manager)With the Proto API, we have worked in a truly prototypal fashion and always created objects, not object factories. If this exercise is really useful remains to be seen, but it is interesting because of its conceptual purity and its closeness to JavaScript’s inheritance roots. You can download the complete source code as proto.js.
Related reading: