Friday, April 1, 2011

Subclass creation and inheritance in JavaScript or how to extend widgets

There are many books and articles describing the inheritance in JavaScript. I'm using Prototype, jQuery an YUI JavaScript frameworks in my old and new web projects. A quite common task for me is an extension of existing widgets. There is a classic article from John Resig which shows a pure simple solution for JavaScript inheritance without using of any frameworks. Nice implementation. I'm going to show my approved techniques with and without frameworks. They are quite simple. They work for me and I would like to share them with readers of my blog.

Assume we have a JS object (widget) called SuperWidget and want to create a subclass of it called ExtendedWidget. Assume ExtendedWidget has a constructor with four parameters and SuperWidget with two parameters.

1) Pure JS
First we create a new constructor for ExtendedWidget and call the super constructor inside of this to make sure that the instance will be correctly initiated. After that we set some new property values. Finally if the constructor is created we set the prototype to a "new SuperWidget".
 
function ExtendedWidget(param1, param2, param3, param4) {
   // call super
   this.SuperWidget = SuperWidget;
   this.SuperWidget(param1, param2);
   
   // set additional properties
   this.param3 = param3;
   var param4 = param4;

   // implement a new public method
   this.myNewMethod = function(a, b) {
      // do something
      ...
   }
   
   // implement a new private method
   var mySecondNewMethod = function(c, d) {
      // do something
      ...
   }
}

ExtendedWidget.prototype = new SuperWidget;
 
This examples also shows a definition of public and private fields and methods. The keyword "this" marks fields and methods with public access and "var" with private one. In this example "param4" and "mySecondNewMethod" can not be accessed outside after ExtendedWidget was instantiated.

2) Yahoo UI
Yahoo library offers a couple of simple calls out-of-box for subclass creation.
 
ExtendedWidget = function(param1, param2, param3, param4) {
   // call super
   ExtendedWidget.superclass.constructor.call(param1, param2);

   // set additional properties
   this.param3 = param3;
   var param4 = param4;

   // do something
   ...
}

// extend super class
YAHOO.lang.extend(ExtendedWidget, SuperWidget);

// implement a new method
ExtendedWidget.prototype.myNewMethod = function(a, b) {
   // do something
   ...
}

// extend an existing method for additional functionality
ExtendedWidget.prototype.someMethod = function(c, d) {
   ExtendedWidget.superclass.someMethod.call(this, c, d);
   
   // do something extra
   ...
}
 

3) jQuery
jQuery doesn't offer this feature directly, but we can call the superclass constructor in the extended object and extend properties by using of "extend" method. The method jQuery.extend() merges the contents of two or more objects together. We need to merge prototypes.
 
ExtendedWidget = function(param1, param2, param3, param4) {
   // call super    
   SuperWidget(param1, param2);

   // set additional properties
   this.param3 = param3;
   var param4 = param4;

   // do something
   ...
}

// merge properties into the first object ExtendedWidget
jQuery.extend(ExtendedWidget.prototype, SuperWidget.prototype);

// implement a new method
ExtendedWidget.prototype.myNewMethod = function(a, b) {
   // do something
   ...
}
 

4) Prototype
Prototype offers the JS inheritance with "Class.create". I don't want to blow up this post, read the official documentation please :-)

That's all. Now we can use ExtendedWidget as the subclass of SuperWidget like this
 
var extendedWidget = new ExtendedWidget(1, 2, 3, 4);
extendedWidget.myNewMethod("Hello", "World");
 

Announcement: In the next post I will show how to extend a PrimeFaces widget (my preferred JSF library) for command button in order to prevent multiple clicks. I will leverage the jQuery based approach 3). But before I want to present a quite special "delicacy" - hooking of PrimeFaces Ajax calls as a kind of callbacks. Anatomy of PrimeFaces events will be revealed. You will be able to "add" any callbacks to any components on-the-fly. As example I have implemented a new component based on the jQuery plugin blockUI to block any piece of page during various Ajax calls.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.