In the 5th edition of my JavaScript book I made the embarrassing mistake of recommending a constructor and method chaining technique that only works for shallow class hierarchies--it works when class B extends A, for example, but not when C extends B and B extends A.
The technique I recommended was to put a superclass property in the prototype object of a class, and then to chain to a superclass constructor by calling this.superclass(). To see why this fails, imagine that we're creating an instance of class C (which extends B which extends A). The constructor C() chains to B() by calling this.superclass(). The constructor method B() is invoked on the same instance of C, however, so when it attempts to chain to A() by calling this.superclass(), it just ends up invoking itself. This incorrect chaining technique is discussed in sections 9.5.1 and 9.5.2, and is also used in example 9-10 and 9-11 at the very end of the chapter. I blogged about this mistake and a possible workaround almost two years ago.
Now, however, O'Reilly is preparing to do a reprint of the book, and I have an opportunity to fix this mistake. Below is a revised code from examples 9-10 and 9-11. I've renamed the defineClass() method to Class() and have modified it so that it automatically does constructor chaining (I was inspired by dojo for this change). More importantly, I've simplified method chaining by defining a global method named chain() for method chaining. If a method overrides a method defined by a superclass (or a "mixin" class) it can invoke that overridden class by invoking chain() like this: chain(this,arguments). (The second argument must be the arguments array of the overriding method, and the first argument must be the object on which that method was invoked.)
The code is below the fold. I think this is interesting JavaScript, and I'd love to have it checked for errors before it goes into print again... Please leave a comment if you think it could be improved! Update: comments are now closed; spammers have struck.
/**
* Class() -- a utility function for defining JavaScript classes.
*
* This function expects a single object as its only argument. It defines
* a new JavaScript class based on the data in that object and returns the
* constructor function of the new class. This function handles the repetitive
* tasks of defining classes: setting up the prototype object for correct
* inheritance, copying methods from other types, and so on.
*
* The object passed as an argument should have some or all of the
* following properties:
*
* name: the name of the class being defined.
* If specified, this value will be stored in the classname
* property of the returned constructor object.
*
* extend: The constructor of the class to be extended. The returned
* constructor automatically chains to this function. This value
* is stored in the superclass property of the constructor object.
*
* init: The initialization function for the class. If defined, the
* constructor will pass all of its arguments to this function.
*
* methods: An object that specifies the instance methods for the class.
* These functions are given an overrides property for chaining.
* They can call "chain(this, arguments)" to invoke the method
* they override. "arguments" must appear literally.
*
* statics: An object that specifies the static methods (and other static
* properties) for the class. The properties of this object become
* properties of the constructor function.
*
* mixins: A constructor function or array of constructor functions.
* The instance methods of each of the specified classes are copied
* into the prototype object of this new class so that the
* new class borrows the methods of each specified class.
* Mixins are processed in the order they are specified,
* so the methods of a mixin listed at the end of the array may
* overwrite the methods of those specified earlier. Note that
* methods specified in the methods object can override (and chain
* to) mixed-in methods.
*
* This function is named with a capital letter and looks like a constructor
* function. It can (but need not) be used with new: new Class({...})
**/
function Class(data) {
// Extract the fields we'll use from the argument object.
var extend = data.extend;
var init = data.init;
var classname = data.name || "Unnamed Class";
var statics = data.statics || {};
var mixins = data.mixins || [];
var methods = data.methods || {};
// Make a constructor function that chains to the superclass constructor
// and then calls the initialization method of this class.
// This will become the return value of this Class() method.
var constructor = function() {
if (extend) extend.apply(this, arguments); // Initialize superclass
if (init) init.apply(this, arguments); // Initialize ourself
};
// Copy static properties to the constructor function
for(var p in statics) constructor[p] = statics[p];
// Set superclass and classname properties of the constructor
constructor.superclass = extend || Object;
constructor.classname = classname;
// Create an instance of the superclass to use as the prototype for
// the new class. Assign it to constructor.prototype
var proto = constructor.prototype = new constructor.superclass();
// Delete any local properties of the prototype object
for(var p in proto)
if (proto.hasOwnProperty(p)) delete proto[p];
// Borrow methods from mixin classes by copying methods to our prototype.
if (!(mixins instanceof Array)) mixins = [mixins]; // Ensure an array
for(var i = 0; i < mixins.length; i++) { // For each mixin class
var m = mixins[i].prototype; // This is mixin prototype
for(var p in m) { // For each property of mixin
if (typeof m[p] == "function") // If it is a function
proto[p] = m[p]; // Copy it to our prototype
}
}
// Copy instance methods to the prototype object
// This may override methods of the mixin classes or the superclass
for(var p in methods) { // For each name in methods object
var m = methods[p]; // This is the method to copy
if (typeof m == "function") { // If it is a function
m.overrides = proto[p]; // Remember anything it overrides
proto[p] = m; // Then store in the prototype
}
}
// All objects should know who their constructor was
proto.constructor = constructor;
// Finally, return the constructor function
return constructor;
}
/**
* This function is designed to be invoked with the this keyword as its
* 1st argument and the arguments array as its 2nd: chain(this, arguments).
* It uses the callee property to determine what function called this
* function, and then looks for an overrides property on that function.
* If it finds one, it invokes the overridden function on the object,
* passing the arguments
*/
function chain(o, args) {
m = args.callee; // The method that wants to chain
om = m.overrides // The method it overrides
if (om) return om.apply(o, args) // Invoke it, if it exists
}
// Example 9-11 demonstrates the methods above
//-----------------------------------------------
// A mixin class with a usefully generic equals() method for borrowing
var GenericEquals = Class({
name: "GenericEquals",
methods: {
equals: function(that) {
if (this == that) return true;
var propsInThat = 0;
for(var name in that) {
propsInThat++;
if (this[name] !== that[name]) return false;
}
// Now make sure that this object doesn't have additional props
var propsInThis = 0;
for(name in this) propsInThis++;
// If this has additional properties then they are not equal
if (propsInThis != propsInThat) return false;
// The two objects appear to be equal.
return true;
}
}
});
// A very simple Rectangle class
var Rectangle = Class({
name: "Rectangle",
init: function(w,h) {
this.width = w; this.height = h;
},
methods: {
area: function() { return this.width * this.height; },
compareTo: function(that) { return this.area() - that.area(); },
toString: function() {
return "[" + this.width + "," + this.height + "]"
}
}
});
// A subclass of Rectangle
var PositionedRectangle = Class({
name: "PositionedRectangle",
extend: Rectangle,
init: function(w,h,x,y) {
this.x = x;
this.y = y;
},
methods: {
isInside: function(x,y) {
return x > this.x && x < this.x+this.width &&
y > this.y && y < this.y+this.height;
},
toString: function() {
return chain(this,arguments) + "(" + this.x + "," + this.y + ")";
},
},
mixins: [GenericEquals]
});
var ColoredRectangle = new Class({
name: "ColoredRectangle",
extend: PositionedRectangle,
init: function(w,h,x,y,c) { this.c = c; },
methods: {
toString: function() { return chain(this,arguments) + ": " + this.c}
}
});
var cr = new ColoredRectangle(1,2,3,4,5);
alert(cr.toString()); // Demonstrate constructor and method chaining




Funny you posted this, i had just attempted the technique in your book and ran into this problem. I ended up with a more "manual" approach inspired by YUI.
This is mostly a horribly bad comment, but I'm curious -- have you inspected the best javascript libraries' (and there particularly base2's) class creation constructs before constructing your own? As you don't (IIRC -- and I may be wrong, as I've misplaced my 5th ed.) mention or relate to libraries in your examples much, like John Resig, for instance, does, it's hard to tell how much of your tips are good by lucky chance of your own acquired experience only or that of the entire field of open source javascript cooperative development. I used to swear by JSDG, but don't really know how it stands in today's competition in the field.
Johan,
My goal with these examples is educational: I want to write interesting code that helps the reader understand. Some of that code may turn out to be useful in practice, but it isn't written for that purpose nor maintained in the way that prototype, base2, dojo and so on are.
I think that demonstrating how to simulate class-based inheritance and method chaining in JavaScript is a very intersting example, but I don't mean to give the impression that it is a necessary or recommended programming technique!
To answer your specific question, I took a look at base2 and dojo. I did not like the way base.js does method chaining: it looked like there was inefficient code behind the scenes to make it work. I was inspired by dojo to make constructor chaining automatic. I'm not happy that my chain() method requires the arguments object to be passed literally to it, but when I saw that dojo has something similar, I figured I could get away with it here.
I have read more than enough implementations of something like this. It is one of the easiest, complete approaches to understand. If you are aiming at purely education I think you have reached it. My only real curiosity would be to see how it performs against other class implementations.
Assigning a new superclass instance to the prototype and then stripping it of its local properties is functionally equivalent to delegation (http://javascript.crockford.com/prototypal.html).
Not only that, but if the superclass has any side-effects outside of the object's instance, you're in trouble. Delegation, once again, fixes this problem.
I'm also unsure as to why you only copy over functions.
Jordan: thanks for your kind words!
Neil: thanks *very* much to the pointer to Crockford's Object.create() function. I'd seen this used before, but I'd gotten so used to doing inheritance the "old" way that I didn't think to do it here. That will be a big improvement.
I copy over only functions because I'm trying to simulate traditional class-based inheritance where methods are inherited and data is not. I could simplify the code and copy everything, I suppose.
Hi, I have hazarded a few amateur suggestions for, listed below. I have provided a bloated implementation at http://www.baconbutty.com.
0. Your example overlooks the ``DontEnum`` bug in InternetExplorer for ``toString`` (i.e. it fails to override "toString" in IE when using ``for in``).
1. As there is a constructor function expression within the code, I wondered whether you wanted all of the ``data`` sticking around in memory as a closure.
2. Allow the ``mixin`` constructor functions to be called in ``constructor`` as well as ``init`` and ``extend``?
3. Allow the constructor to inherit static properties and methods on the ``extend`` object and the ``mixin`` constructors?
4. The mixins are being added to the same prototype object as the methods. Might it be clearer to separate them into their own prototpe in the prototype chain, sitting between the class prototype and its superclass prototype?
5. Might it be useful to consider further where the ``mixin`` methods sit in the ``override`` chain? At present the choice is that if a ``mixin`` method has the same name as a method on the ``extend`` prototype chain, then the ``mixin`` method overrides but does not chain to the ``extend`` method, it chains to the ``mixin's`` own ``override`` chain.
6. I don't know, but it might be useful to add a ``name`` property to each ``method``, perhaps useful for reflection or some other purpose in the future.
7. The ``chain`` function only passess on the ``args`` variable, which is the arguments object from the calling function. This means that the calling function cannot explicitly set the arguments for the chained method. Also could we avoid passing the ``o`` by making ``chain`` a method on the prototype? I like ``callSuper`` instead of ``chain``.
I understand the problem you're trying to solve by not copying the non-function properties over, but I think that makes it hard to maintain this solution. I think if we're emulating true inheritance, we'd need to do a deep clone on these non-function properties. At the same time, immutable data should be fine to copy over. It might be an acceptable compromise to force users to redeclare arrays and objects, but copy everything else. And even then, you should provide some mechanism to alert users that the data that you didn't copy over doesn't appear in their overrides.
Also, even if this is acceptable in your mixins property, how should one, using this syntax, add new non-function properties to this new Class's prototype?
@Julian Turner makes several excellent points, and for #7, it seems like it might be worth adding an extra optional attribute to the chain function that allows the user to override the arguments that get passed. eg chain(this, arguments ["foo", 1])
Julian,
Thanks for your detailed comments (and further
details at your site). I think yours is probably
the best comment I've ever gotten at my blog, and
it certainly demonstrates that this blog has a
terrible comment entry and comment display
interface!
> Hi, I have hazarded a few amateur suggestions
> for, listed below. I have provided a bloated
> implementation at http://www.baconbutty.com.
> 0. Your example overlooks the ``DontEnum`` bug
> in InternetExplorer for ``toString`` (i.e. it
> fails to override "toString" in IE when using
> ``for in``).
I was not aware of this partiular bit of IE
breakage. Have you verified that the bug still
exists in current versions of IE? It sounds like
you suggest manually copying toString and valueOf
if they exist?
> 1. As there is a constructor function expression
> within the code, I wondered whether you wanted
> all of the ``data`` sticking around in memory as
> a closure.
I'm not worried about memory usage for this
example. Note that your modification alters an
object belonging to the caller. You should
probably make a defensive copy of the object
before playing with it!
Also, as you note in the comments of your code,
some of the local variables are there purposely to
be captured in the closure of the constructor
function.
> 2. Allow the ``mixin`` constructor functions to
> be called in ``constructor`` as well as ``init``
> and ``extend``?
I fear there is a can of worms there. Possibly
useful, but not something that fits in this
chapter of my book, given the discussion that
precedes the example.
> 3. Allow the constructor to inherit static
> properties and methods on the ``extend`` object
> and the ``mixin`` constructors?
I don't like inheritance of statics, so I don't
want to go there myself.
> 4. The mixins are being added to the same
> prototype object as the methods. Might it be
> clearer to separate them into their own prototpe
> in the prototype chain, sitting between the
> class prototype and its superclass prototype?
I tried a couple of variations on this and always
went back to they way I have it. Earlier in the
chapter I describe "borrowing" functions by
copying them, so it makes sense to do it that way
for this example. Also, giving the mixin functions
their own object in the prototype chain sets up an
expectation that the instanceof operator should
work for the mixed in classes, and I don't believe
it is possible to make it work.
> 5. Might it be useful to consider further where
> the ``mixin`` methods sit in the ``override``
> chain? At present the choice is that if a
> ``mixin`` method has the same name as a method
> on the ``extend`` prototype chain, then the
> ``mixin`` method overrides but does not chain to
> the ``extend`` method, it chains to the
> ``mixin's`` own ``override`` chain.
The implementation of chaining that I have chosen
involves setting an "overrides" property on one
function referring to the function that it should
chain to. This is static, but efficient as it
does not involves searching the prototype chain
for a named method in order to chain. But, it
precludes mixins from chaining along the
inheritance chain of the class into which they are
mixed: if a mixin was mixed into two different
classes, the overrides properties applied by one
class would obliterate the override properties
applied by the other. (It makes me want to be
able to make a copy of a function g=Function(f) to
get a new object with the same executable content.
Alas, this is not possible.)
> 6. I don't know, but it might be useful to add a
> ``name`` property to each ``method``, perhaps
> useful for reflection or some other purpose in
> the future.
I had this in there, and also an "owner" property
to refer to the class that defines the method. I
took it out because I wasn't making any use of it,
and I've got tight space constraints to fit the
modified example into exactly the same space of
the old one for a reprint. I might put this back
in.
> 7. The ``chain`` function only passess on the
> ``args`` variable, which is the arguments object
> from the calling function. This means that the
> calling function cannot explicitly set the
> arguments for the chained method.
This is a very sensible upgrade to chaining. I
think dojo allows that. But I purposely left it
out of my example for simplicity. In production
use, you'd want to allow explicitly specified
arguments. (Thought that does make it harder to
explain to users why they still have to pass the
arguments array!)
> Also could we avoid passing the ``o`` by making
> ``chain`` a method on the prototype? I like
> ``callSuper`` instead of ``chain``.
I started out this way, chaining with
this.chain(arguments) instead of
chain(this,arguments). The code to make sure that
chain was defined as an instance method (but was
only defined once on the prototype chain rather
than for every class) was kind of clunky. Also,
I'll have to introduce this chain() method earlier
in the chapter, and it will end up being a global
there, so I kept it that way here.
Thanks again for your thoughts!
Neil,
> Also, even if this is acceptable in your mixins
> property, how should one, using this syntax, add
> new non-function properties to this new Class's
> prototype?
You shouldn't :-) I guess my thinking was that
I'm modelling a strict class-based system, where
methods are inherited and data is kept with the
instance. What's the use-case that makes you want
non-function properties there? Can you give me an example?
> @Julian Turner makes several excellent points, and
> for #7, it seems like it might be worth adding an
> extra optional attribute to the chain function
> that allows the user to override the arguments
> that get passed. eg chain(this, arguments ["foo",
> 1])
I agree that for prodution use this would be
necessary. I suspect I don't want the added
complexity in the book for this reprint, but I'll
see about adding that.
David,
Excellent example, but as Julian pointed out, some care needs to be taken to work around browser quirks.
1) The "DontEnum" bug is still present in IE7 (not sure about IE8). Manually copying properties seems like the best solution. It's also good to remember that not only toString/valueOf are skipped but any method with `DontEnum` in the prototype chain (i.e. all of the native Object.prototype methods - toLocaleString, hasOwnProperty, propertyIsEnumerable, etc.)
2) Inheriting via "parent" invocation is usually discouraged - not only could it affect the created object, but could also be computationally expensive. "Proxy" approach (aka Crockford's Object.beget) works perfectly around these deficiencies.
3) Filtering properties through "typeof 'function'" seems weird. Moreover, `typeof` will return "function" for RegExp objects in Mozilla, and NodeLists in WebKit, resulting in inconsistency.
4) "instanceof Array" will return false for array objects created within another document (e.g. iframe)
On a side note, wouldn't it make sense to let pass plain objects as mixins (i.e. not only constructors with prototype's)?
Best,
kangax
David,
Thank you very much for your response to my comments, which make a lot of sense.
0. DontEnum. I definitely observed the bug on IE6 and 7, and it seemed quite well documented on the Internet. I wouldn't have raised it if I hadn't immediately encountered the problem when trying to run your example. I have tested IE 6 again now, and it is there. I will double check IE7 later. It only affects "for .. in" (i.e. Enumeration). You are correct, the answer seemed to be to manually address "toString", and "valueOf" if desired.
1. Thanks for the advice about making a defensive copy. I hadn't thought of that.
2. I think you are right about the constructor can of worms.
3. I take your point about not doing inheritance of statics. I also get the order wrong for this as well I think.
4./5. On the question of mixins, I can see why you might want to keep it as it is, and the problems about putting them into the new override chain. Also, doing so runs into the "defensive" copy issue again, in that I tamper with the "override" property; and as you point out, a defensive copy of a Function will lose its execution context.
6. I must admit, I don't really use the name property it in my own implementation.
7. On the chain function, have you looked at Dean Edwards Base 2 solution. See "_override" in his base2.js file. In effect he has a property called "base" on the instance object. When you have an override method, he wraps the override method in another function, and in that other function (a) alters the "base" property to refer to the overriden method just before calling the override method (so that the override method can simply call "this.base()"), (b) calls the override method, and (c) then changes the "base" property back to its previous value after the override method has returned.
I do find it a bit odd having to pass the arguments array, but I guess this is the standard way to do it. Whether for security or otherwise the "arguments.caller" property just does not seem to find favour.
I can see your point about only defining "chain" once. I do this by having a simple base class on which my "callSuper" sits, from which all other classes inherit then inherit.
_______________________________________
@kangax : I have certainly found that by keeping shared methods/shared properties belonging to a Child off the object created using "Child.prototype = new Parent()", means that the "proxy" prototype can then have properties (e.g. superProto) which refer to the "new Parent()" created instead through "proxy.prototype = new Parent()", without circular references getting in the way (and the shallow inheritance problems you started with). Does this make sense?
i.e. example chain
proxy1.prototype = new Base();
^
Parent.prototype = new proxy(); [Parent shared methods go here]
[Parent.prototype.superProto = proxy1 prototype;]
^
proxy.prototype = new Parent()
^
Child.prototype = new proxy(); [Child shared methods go here]
[Child.prototype.superProto = proxy prototype;]
^
Child.instance
So you can now look up the prototype chain through Child.superProto.superProto in all browsers without circularity.
There are probably other problems this leads to.
kangax,
In response to Julian, I've updated my example with special code to handle toString. But I'm going to ignore the other non-enumerable properties for now.
In response to Neil, I'm now using a variant of beget to create the prototype objects instead of calling the superclass constructor.
And I've even stopped filtering for function objects, even though I can't think of a use case for class-based inheritance where data would go in the prototype!
I just haven't updated the example code to show my changes!
I'm not really worried about cross-frame invocation of this method. Do you have a one-line alternative to instanceof Array to propose? In the context of my book you can't just say "use Prototype", however :-)
You're right that it does kind of make sense to allow plain objects as mixins along with constructors. I'll think about this.
Julian,
Yes, I looked at base2, and I really didn't like the way chaining is done there. I haven't attempted to benchmark it--the performance of that approach may be fine, but still, that kind of dynamic tweaking just doesn't seem right!
David,
There are lots of different uses for attaching non-functions to a prototype. But I think I've come up with an example that I think everyone will be able to understand regardless of their philosophies.
Many times, I'll assign an instance of an RPC class to a prototype. This way, I can do something like:
rpc: new dojox.rpc.Service("rpc.smd"),
getHistory: function(days){
return this.rpc.getHistory({ limit: days || 10 });
}
Neil,
Your point, I suppose, is that this way a subclass can override the rpc object with some other, differently configured, instance of the Service class, thereby changing the behavior of the getHistory() method. I guess you've convinced me.
David
I can see why you might have reservations about wrapping your methods in anonymous functions to enable a call to base.
I have been playing around with it, and it has lots of potential. Wrapping you can even go as far as implementing the "super" and "base" keywords in Java and C# identically, applying not just to the method at hand but calling any method in the base class, by wrapping the base class prototype.
I suppose all that wrapping may have some performance issues if you are calling super methods for some processing intensive tasks, and it may have memory issues if you wrap too many methods, and instinctively you are one step removed from your method (but does that really matter).
Ultimately, coming back to where you started, your method has the clear advantage that it is clean, easy to understand and try out, which I guess must be your main objective for a teaching book. The fact that your example gave rise to a lot of comment is probably a testament to its lack of obsurity.
Regards
Julian
Hi David,
Let me start by saying your JavaScript book is superb; it?s my standard printed reference. Excellent work!
I wrote the chapter on dojo.declare?which is analogous to the Class function you discuss above?in the new Pragmatic Programmers book on dojo (Mastering Dojo). During this work, I did quite a bit of research and thinking about this subject. This stuff is really interesting in my view...but very hard to get right. Here are a couple of observations:
1.
The function you propose is excellent as a teaching example. It will also work quite well defining many, real-world class hierarchies. However, it will not handle some class derivation problems as some people may expect?particularly when coming from other languages (see below). This is also true of dojo.declare.
2.
The function assumes that initializer argument signatures are identical between subclass, superclass, and mixins. This is often true when using a single object to initialize instances, but often false when using positional arguments. Also, positional arguments tend to be used for simple classes that are frequently constructed. For example, who wants to write ?new point({x: 1, y: 2})? compared to ?new point(1, 2)?. And these kind of classes often show up on the bottom of the class hierarchy (sometimes due to mistaking a ?has-a? relationship for an ?is-a?). dojo.declare has limited support to fix this problem, but the dojo solution isn?t general either. I wrote lots about this, and solutions, in the book.
3.
The whole mixin thing opens a huge can of worms. But, for starters, if the mixin, itself, is defined in terms of a multi-level class hierarchy, then the concept of chaining through mixin superclass methods won?t work. Also, what if the mixin methods depend on some data in the mixin prototype? Since only functions are copied, this data will be lost and these methods won?t work. Finally, changing a mixin class?s prototype will not change the behavior of a class that?s mixed in that mixin class. This can be counter-intuitive for one view of how the run-time system should work.
Kind Regards,
Rawld Gill
Rawld,
Thanks for your comments. I'm aware of the issues you raise, but am constrained by keeping the example understandable, and keeping it to the same size as the example that is currently printed in the book--since I'm fixing it for a reprint, it can't grow much.
But I do need to document the fact that superclass chaining requires constructor arguments to be in the same order. (Subclasses can add arguments, but must preserve all superclass constructor arguments, in the same order.) Or I need to modify it to make the chaining explicit.
And the more I think about mixins, the more I consider removing them. My chapter already has a stand-alone borrowMethods() method, and maybe I can leave mixins out of this function...