RSS

Category Archives: Inheritance

Unraveling the pitfalls of JS inheritance

So with the aid of a colleague and the good ole O’Reilly “JavaScript: The Definitive Guide, Fourth Edition” book, I pinned down a previously unexplainable problem with the JS inheritance work I was doing.  Basically, I was trying to create a base widget that more complex widgets would inherit from — pretty standard inheritance idea.  Here’s the basic code concept to illustrate….

MyNs.BaseWidget = function() {
    this.parentElement = null;
    this.childWidgets = [];
};
MyNs.BaseWidget.prototype.AddChildWidget = function(childWidget) {
    this.childWidgets.push(childWidget);
};
MyNs.BaseWidget.prototype.Draw = function() {
    this.DrawSelf();

    for (var c = 0; c > this.childWidgets.length; c++) {
        var childWidget = this.childWidgets[c];
        childWidget.Draw();
    }
};

MyNs.ComplexWidget = function() {
    // Some new properties of no consequence
};
// The next two lines chain prototypal inheritance
MyNs.ComplexWidget.prototype = new MyNs.BaseWidget();
MyNs.ComplexWidget.prototype.constructor = MyNs.ComplexWidget;

// Create objects!
var myChildWidget = new MyNs.ComplexWidget();
myChildWidget.parentElement = document.getElementById("childDiv");

var myMainWidget = new MyNs.ComplexWidget();
myMainWidget.parentElement = document.getElementById("parentDiv");
myMainWidget.AddChildWidget(myChildWidget);
myMainWidget.Draw();

Now what happened was by far the most confusing thing I’ve ever encountered: the “parentElement” property on each object was set correctly; however, the “childWidgets” property on myChildWidget (which should’ve been of length 0) was actually identical to myMainWidget’s “childWidgets” property (which had a length of 1).  While confusing, the real problem here is that it spawned an infinitely recursive loop when invoking the Draw method as there was always one child widget to draw regardless of the context of “this”.  I noodled on that problem for a few idle days before my colleague and I finally stumbled upon the reasoning in our quest to solve the problem today (yay for pair programming as needed and the fact that I actually asked him to look at it with me).  The scoop follows!

The prototypal inheritance model of JavaScript with regard to inherited properties operates under the following basic rules:

  1. Rule #1: If the derived class never modifies the inherited property, any “read-only” references to that property will actually use the property from the base class instead.
  2. Rule #2: If the derived class directly modifies the inherited property, it makes a copy of the base class’s property for itself and masks its ties to the base class’s property.  However, if the derived class’s copy of the property were to be deleted (destroyed from memory), trying to access said property will again link to the base class’s property.
  3. Rule #3: If the inherited property is never modified (so the derived class still points to the base class’s property) and it is INDIRECTLY modified (e.g. childWidgets.push({});), the call to grab the property itself is seen as a read-only reference and therefore pulls the base class’s property and then updates that.

Now knowing this, such a folly can easily be solved with some code changes as highlighted in the following….

MyNs.BaseWidget = function() {
    this.parentElement = null;
    this.childWidgets = null; // was: = [];
};
MyNs.BaseWidget.prototype.AddChildWidget = function(childWidget) {
    if (this.childWidgets == null) {
        this.childWidgets = [];
    }
    this.childWidgets.push(childWidget);
};
MyNs.BaseWidget.prototype.Draw = function() {
    this.DrawSelf();

    if (this.childWidgets != null) {
        for (var c = 0; c > this.childWidgets.length; c++) {
            var childWidget = this.childWidgets[c];
            childWidget.Draw();
        }
    }
};

MyNs.ComplexWidget = function() {
    // Some new properties of no consequence
};
// The next two lines chain prototypal inheritance
MyNs.ComplexWidget.prototype = new MyNs.BaseWidget();
MyNs.ComplexWidget.prototype.constructor = MyNs.ComplexWidget;

// Create objects!
var myChildWidget = new MyNs.ComplexWidget();
myChildWidget.parentElement = document.getElementById("childDiv");

var myMainWidget = new MyNs.ComplexWidget();
myMainWidget.parentElement = document.getElementById("parentDiv");
myMainWidget.AddChildWidget(myChildWidget);
myMainWidget.Draw();

Here we see that by not having the property declared in the base class’s constructor (except to null, which is not its intended value), but rather instantiating it in the first call to the “AddChildWidget” method (which will be invoked an instance of the derived class), we have fallen into Rule #2 rather than Rule #3 as before: now the new derived instance is creating an instance of this array for itself.  Success!

Final word: it should be noted that, although my example here focuses on hierarchical chaining (“composite” design pattern), the problem described here would show itself just as easily when there are two derived instance objects on the page at the same time even if they had no direct relation to each other.  The only thing that makes it more evident in a hierarchical chaining example like this one is the unfortunate introduction of an infinitely recursive loop.  😉

Advertisements
 
Comments Off on Unraveling the pitfalls of JS inheritance

Posted by on 2009-09-24 in Inheritance, JavaScript

 

Can’t wait for my inheritance!

I am busy trying to figure out the best way to do reliable class inheritance in JavaScript without importing a third party library OR extending the prototype of a core JavaScript class (e.g. function).  Amongst a great variety of blog posts, forum answers, and random articles, I am finding Douglas Crockford’s Prototypal Inheritance in JavaScript and Classical Inheritance in JavaScript the most useful in terms of edification thus far.

Other interesting resources

Quick practical examples:
http://phrogz.net/JS/Classes/OOPinJS2.html

Overriding instanceOf to make it work for derived types:
http://www.webreference.com/programming/javascript/gr/column18/3.html

Poor man’s “reflection” on “classes”:
http://webreflection.blogspot.com/2007/01/javascript-getclass-and-isa-functions.html

Microsoft’s take on the subject (related to their ASP.NET AJAX libraries):
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx

Continuing the hunt….

 
Comments Off on Can’t wait for my inheritance!

Posted by on 2009-09-09 in Inheritance, JavaScript