<<Series
Description>>
The AJAX from Scratch
series of articles describe fundamental techniques needed to develop AJAX Rich
Internet Applications in JavaScript from scratch. Each article focuses on a
particular (usually little-covered) aspect of developing browser-side
functionality without the use of commercial or server-based frameworks. The
techniques described are additionally illustrated in Gravey, a small,
but real-world, JavaScript framework for AJAX and RIAs.
<<Title>>
AJAX from Scratch: Implementing
Multiple Inheritance in JavaScript
Part 2 of Implementing “Real” Classes in JavaScript
<<Author>>
Bruce Wallace
http://www.PolyGlotInc.com/
bruce.wallace@acm.org
<<Abstract>>
In part one of Implementing “Real” Classes in JavaScript[1] an implementation was presented to emulate Java-like classes in JavaScript. In this followup, that implementation is extended to enable multiple inheritance. Both Java-like multiple Interface[3] inheritance, and multiple Class inheritance[2] as found in other object oriented languages, are made possible even though JavaScript supports only single Prototype inheritance[5]. A pragmatic approach is taken to resolve ambiguities[4] that results in simple usable code.
<<Body>>
…this section TBD…
The Platform Implementation
While the complete documented version of the platform[6]. is contained in a few JavaScript include files, the compact, standalone code in Listing 3 implements the basic technique. Lines 19-39 implement the new “implements” capability; interfaces (i.e. methods) are attached, and, “super” references are linked, all in class priority order. Lines 7-11 add the new extra version of “super” that allows the parent class to be specified in order to disambiguate the super method. Lines 12-16 add the new method that replaces the instanceof operator when checking for “implements” inherited classes.
1
Class(GrvObject); //special root class
2 function
GrvObject(){
3 this.souper = function(){
4 var superMethod =
this.souper.caller.souper;
5 return (superMethod) ? superMethod.apply(
this, arguments ) : null;
6 }
7 this.souper_ = function( superclass ) {
8 var superMethod =
this[superclass.cname]._[this.souper_.caller.mname];
9 var theArgs = Array.prototype.slice.call(arguments,1);
10 return
(superMethod) ? superMethod.apply( this, theArgs ) : null;
11 }
12 this.isInstanceOf
= function( aClass ){
13 if
(aClass.cname==null) return false;
14 var m = this[
aClass.cname ];
15 return( m
&& m instanceof Function );
16 }
17 }
18
19 function grvImplements(){
20 var
sexemplar,s,m,N = arguments.length;
21 var rexemplar =
this.rawExemplar;
22 var exemplar = this.prototype;
23 for (var i=0;
i<N; ++i){
24 sexemplar =
arguments[i].prototype;
25 for (var x in
rexemplar){
26 if
(!(rexemplar[x] instanceof Function)) continue;
27 m = exemplar[x]; if (m.souper) continue;
//already linked!
28 s = sexemplar[x];
29 if (s
&& (s instanceof Function)) m.souper = s;
30 }
31 }
32 for (var i=0;
i<N; ++i){
33 sexemplar =
arguments[i].prototype;
34 for (var x in
sexemplar){
35 s =
sexemplar[x];
36 if ( exemplar[x]===void 0 && s
instanceof Function ) exemplar[x] = s;
37 }
38 }
39 }
40
41 function grvExtends( superClass ){ //link super and sub
class
42 var sexemplar =
this.baseClass.prototype =
43
((this==GrvObject) ? null
: superClass.prototype);
44 var exemplar = this.prototype = new
this.baseClass();
45 for (var x in
exemplar){
46 var m = exemplar[x]; if (!(m instanceof Function))
continue;
47 m.mname
= x; if (! sexemplar
) continue;
48 var s =
sexemplar[x];
49 if (s
&& (s!=m) && (s instanceof Function)) m.souper = s;
50 }
51 if
(exemplar.konstructor==null) exemplar.konstructor = function(){};
52 if (superClass==GrvObject)
this.rawExemplar = exemplar;
53
exemplar[this.cname] =
exemplar.konstructor;
54
exemplar.konstructor._ = exemplar;
55 return this;
56 }
57
58 function grvFuncName(f){ //extract name from function
source
59 var s =
f.toString().match(/function\s*(\S*)\s*\(/)[1];
60 return s ? s :
"anonymous";
61 }
62
63 function Class( theClass ){
64 var originalClass
= theClass;
65 var
className = grvFuncName( theClass );
66 self[ className ]
= theClass = function _wrapper_(){
67 arguments.callee.prototype.konstructor.apply(
this, arguments );
68 }
69
theClass.cname =
className;//FYI,netscape&firefox break with ".name"
70
theClass.baseClass = originalClass;
71
theClass.Extends =
grvExtends;//so we can call as methods...
72
theClass.Implements= grvImplements;
73
theClass.Extends(GrvObject);//required here even if overridden later
74 return theClass;
75 }
Listing 3. The
multiple inheritance basic implementation (grvObjects.js)
The Class and grvExtends functions (lines 41-75) work essentially the same as the single inheritance version; they merely keep references to more internal objects to support grvImplements and the new souper_ method.
With the presented expanded implementation, JavaScript developers can take advantage of multiple Interface and Class inheritance, thus enhancing the use of the robust design patterns needed for AJAX and RIA applications. Use of this expanded technique does not preclude mixing in other techniques nor legacy code thus allowing it to be added to existing code.
<<Examples>>
<<References>>
1. http://www.developer.com/lang/jscript/article.php/3657486
2. http://en.wikipedia.org/wiki/Multiple_inheritance
3. http://en.wikipedia.org/wiki/Interface_%28Java%29
4. http://en.wikipedia.org/wiki/Diamond_problem
5. http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Property_Inheritance_Revisited:No_Multiple_Inheritance
6. http://www.gravey.org/
7. http://www.polyglotinc.com/AJAXscratch/Class/examples/
<<About the Author>>
As principal consultant of PolyGlot, Inc., Bruce Wallace has provided consulting and custom computer software development services around the world. Projects have been completed in Sydney Australia, Perth West Australia, "Silicon Valley", "Route 128" MA, Austin TX, Atlanta GA, and Charlotte NC.
<<Copyright>>
ă Copyright 2007, PolyGlot, Inc.