<<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.

Conclusion

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.