Posted in Dojo Cookies
A hidden gem of Dojo.declare - overcoming the limits of multiple inheritance
One of the greatest things of dojo.declare is that it simulates one of the core elements of OO - inheritance. Moreover, it allows having several parents to the same object.
In this case the object inherits all the functionality of all of its parents. One of the basic problems in multiple inheritance is what to do when an object A extends two other objects - B and C, both have a function called doSomthing
. In this case at least one of the implementations of doSomething
, either B’s or C’s will not get called when A’s doSomething
is called. Let’s illustrate it in code:
dojo.declare("myPackage.B",null,{ doSomething: function(){ alert("I'm doing something in B"); } }); dojo.declare("myPackage.C",null,{ doSomething: function(){ alert("I'm doing something in C"); } }); dojo.declare("myPackage.A",[myPackage.B, myPackage.C],{ doSomething: function(){ alert("I'm doing something in A"); } }); dojo.declare("myPackage.A1",[myPackage.B, myPackage.C],{ }); dojo.declare("myPackage.A",[myPackage.B, myPackage.C],{ doSomething: function(){ this.inherited("doSomething",arguments); } }); var a = new myPackage.A(); var a1 = new myPackage.A1(); var a2 = new myPackge.A2(); a.doSomething(); // alerts: I'm doing something in A a1.doSomething(); // alerts: I'm doing something in C a2.doSomething(); // alerts: I'm doing something in B
As you can see, if no implementation is provided for the doSometing
function, then the object that its doSomething
function will be invoked is the object which is the last object in the parents list that has a doSomething
function. Using inherited
is similar to using super
in Java. However, there is a possibility to call other parent’s doSomething
function, and this is due to the fact that in Javascript, each object has a prototype, which holds all the implementations of its functions, and thus making them accessible to invocation from the outside. Since dojo.declare receivers the list of the parent objects’ constructors as the second parameter, it is possible to access their prototype and invoked their specific functions. Moreover, using the apply
function allows you to change the context object of the function, and thus simulate inheritance of the parent object function for a specific call. In the above example, if you’de like to call both B’s and C’s doSomething
functions, all you need to do is the following:
dojo.declare("myPackage.A3",[myPackage.B, myPackage.C],{ doSomething: function(){ myPackage.B.prototype.doSomething.apply(this, arguments); myPackage.C.prototype.doSomething.apply(this, arguments); } }); var a3 = new myPackage.A3(); a3.doSomething(); // alerts: I'm doing something in B and after that I'm doing something in C
This is particularly important if you create widgets that extend several other widgets. Since in Dojo widgets have a specific path to go through during initialization, with several entry point in key moments during the initialization process (e.g., postMixInProperties and postCreate ), it is recommended to call to all of the parents entry points implementations (if your widget overrides them) in order not to cause initialization problems.
Tags: dojo.declare