Super Constructor Calls in JavaScript
Friday, August 17th, 2007I have previously shown a simple system for creating “classes” in JavaScript with Java-like inheritance. One limitation of this system is that calling a superclass constructor requires you to repeat the name of the superclass at the calling site:
extcls(Point, function Rect(x, y, w, h) { Point.call(this, x, y); this.w = w; this.h = h; })
This is both ugly and unnecessarily limiting. Furthermore, there is no guarantee that the superclass constructor is actually called. In Java, the compiler automatically inserts a super() call at the beginning of a constructor if there is no explicit call to a superclass constructor. This behavior cannot be easily duplicated in JavaScript but it should at least be possible to force an explicit superclass constructor call and throw an exception if such a call does not happen.
We cannot quite use Java’s syntax, either, because firstly, the super keyword is reserved in JavaScript and secondly, we need to invoke the super call through the this object, but we can get close by calling it this.superc (with the “c” standing for “constructor”). Here’s the Rect constructor using the new syntax:
extcls(Point, function Rect(x, y, w, h) { this.superc(x, y); this.w = w; this.h = h; })
Where and how can this superc function be defined? The previous example with a base class and one subclass makes it look deceptively simple. Let’s add another class to the hierarchy:
extcls(Rect, function ColoredRect(x, y, w, h, color) { this.superc(x, y, w, h); this.color = color; })
When you create in instance of ColoredRect, the this.superc() call in ColoredRect has to call Rect() but the this.superc() call in Rect has to call Point(), and it’s the same this object they’re calling it on! The only way to achieve this is by reassigning superc to the correct function before each constructor is called.
Fortunately, this is possible because superc is always called from the pseudo-constructors that are passed to extcls and these pseudo-constructors are always called from real constructors which are created on the fly by extcls. We can simply assign the correct superc function in the generated constructors before invoking the pseudo-constructors. And we can make sure that superc has been called by having it set a local flag and checking that flag when the pseudo-constructor returns. Here’s the updated extcls function with the new features:
function extcls(parent, init) { var cons = function cons() { var called; this.superc = function() { parent.apply(this, arguments); called = true; }; if(arguments.length == 1 && arguments[0] === cons) return; init.apply(this, arguments); if(parent && parent.__init && !called) throw new Error("superc() was not called in "+init.name+"()"); }; cons.toString = function() { return "[Generated constructor for class "+init.name+"]"; }; cons.__init = init; if(parent) cons.prototype = parent.__init ? new parent(parent) : new parent(); if(init.name) self[init.name] = cons; return cons; }
Note that the superc() call may be omitted if no parent class has been given (in which case object is used) or if the parent class is a plain JavaScript constructor that was not defined by defcls or extcls.

