Friday, May 29, 2009

Javascript Inheritance

When I first started embarking on larger scale JavaScript projects (not just the standard event handler snippets) it took me a while to adjust to the differing inheritance style since i was used to class based programming. Initially I flirted with the Microsoft AJAX.NET approach, which attempts to bolt on a class based, strongly typed inheritance model onto JavaScript (even to the point of mimicking enumerations and interfaces), but eventually I realized that it was best to use the language the way it was intended to be used.

After a bit of searching among the variety of approaches out there, I ended up using the parasitic inheritance model proposed by Douglas Crockford. The essence of this approach is having the constructor for a subclass instantiate an instance of its superclass, modify it by adding methods, and then returning the modified object. A simple inheritance would look like this:

   1:  car= function(manufacturer) {

   2:      // class we inherit from

   3:      var me = new vehicle(manufacturer);

   4:      me.honkHorn = new function() {

   5:          // do stuff

   6:      };

   7:      return me;

   8:  }


  10:  var myBlueVolvo = new car= ("Volvo");

This seems pretty natural and gives most of what I was looking for (code reuse and some variable hiding) without torturing the language too badly.

I do occasionally need to call methods in the superclass from the subclass though. Douglas implements a relatively complex "sugar" that automatically provides reference to a "uber" object that mimics the "base" object in C#, but I was worried that this was a lot of extra code for something I really only do with a handful of functions. Complexity is bad.

Instead, when I need to reference an overridden method in the superclass, I took advantage of JavaScript closures to provide a simple way to call a superclass method. Here is an example:

   1:  var super = me.honkHorn; 

   2:  me.honkHorn = new function() {

   3:      // call the method on the superclass

   4:      super.honkHorn();


   6:      // now do stuff in the subclass

   7:  };

By saving the superclass function in the super var, it gets captured and is still around to be called, even though it is no longer references by the new object as a public function.

No comments: