Helma Logo
main list history

JavaScript Inheritance Sugar - Lehni

This post about Dean Edward's Base Class for JavaScript Inheritance started the discussion about JavaScript OOP in Helma.

Hannes came up with his own impementation, and in parallel, without being aware of the feature in Hannes' version, I was following the discussion on Dean's page and found Ben Newman's implementation for Prototype, which looked very clean and which I used as a base for my own improvements (described in this post):

I then finally came across Hannes' implementation and realized it solves some problems in a cleaner way: For example it does not copy over methods from base class, but creates a proper inheritance chain using prototypes. His code was also less obscure, but at the same time longer.

I started to combine both efforts into one library and address some more issues. The result is very tight and offers a lot of functionality. I am pretty happy with it and decided to share it here. Bellow a short description of the features.

Files

nametypesize
base-commented.jsundefined bytes
base.jsundefined bytes
base-demo.htmlundefined bytes

Description

Classes are defined by using Object.extend. The function takes two hash-lists (JS Objects), the first one for the instance fields, the second one for static class fields. The static list is optional. Inheritance is implemented for both, so static class methods can be inherited from base classes and called through $super too. Each class that is created in such a way recieved the static functions "extend" and "inject". extend does the same as Object.extend, .inject works similarly and has the same arguments, but instead of creating a new class, it simply adds the fields to the existing class, so modification of classes at runtime is possible. If a function is overriden in such a way, $super can be used to call the previous definition of that function before the call to inject.

A change was made to not "hardcode" the function if $super is used, but to look it up each time instead. Before, changes to the $super method after inheritance where not reflected in the function that inherited from the super class.

Note that the constructor function's name was changed to "initialize", just like in Prototype, because "constructor" causes an error on some browsers (e.g. Mac IE).

Examples

 var ClassOne = Object.extend({
 	// instance fields
 	$constructor: function() {
 		writeln("Creating ClassOne instance");
 	},
 	test: function() {
 		write("Hello from ClassOne");
 	},
 	$static: {
 	 	// class fields
 		test: function() {
 			write('Static Hello from ClassOne');
 		},
 		// define a constant
 		PI: Math.PI
 	}
 });
 var ClassTwo = ClassOne.extend({
 	$constructor: function() {
 		writeln("Creating ClassTwo instance");
 	},
 	test: function() {
 		this.$super();
 		writeln(" - Hello from ClassTwo");
 	},
 	$static: {
 		test: function() {
 			this.$super();
 			writeln(' - Static Hello from ClassTwo');
 		}
 	}
 });
 writeln();
 writeln("// var obj = new ClassTwo();");
 var obj = new ClassTwo();
 writeln();
 writeln("// obj.test();");
 obj.test();
 // now modify the function directly:
 ClassOne.prototype.test = function() {
 	write("Hallo aus KlasseEins");
 }
 writeln();
 writeln("// again with modified function in base class after inheritance");
 obj.test();
 // The same happens with static class functions:
 writeln();
 writeln("// ClassTwo.test();");
 ClassTwo.test();
 // now modify the static function directly:
 ClassOne.test = function() {
 	write("Statisches Hallo aus KlasseEins");
 }
 writeln();
 writeln("// again with modified static function in base class after inheritance");
 ClassTwo.test();
 writeln();
 writeln("// Note that not only functions are inherited");
 writeln("ClassTwo.PI = ", ClassTwo.PI);

Output:

 // obj.test();
 Hello from ClassOne - Hello from ClassTwo
 // again with modified function in base class after inheritance
 Hallo aus KlasseEins - Hello from ClassTwo
 // ClassTwo.test();
 Static Hello from ClassOne - Static Hello from ClassTwo
 // again with modified static function in base class after inheritance
 Statisches Hallo aus KlasseEins - Static Hello from ClassTwo
 // Note that not only functions are inherited
 Two.Pi = 3.141592653589793

Prototype Compatibility

With a simple addition, this code should become again compatible with Ben's prototype branch, to test it out:

 // insert code from extend.js here, before the definition of
 // Object.extend in Prototype, that does something different:
 // Safe our Object.extend, so it can be used in Class.create
 Object._extend = Object.extend;
 Class = {
 	create: function(decl, stat) {
 	 	return Object._extend(decl, stat);
 	}
 }
 // Rest of Prototype follows here

Links to this page: Helma 2 alpha 1, Mocha Inheritance

Comments

#1 by luchkovsky at 2007/04/18 19:06

At the first, I’d like to say thank you for the article and great work.

There is another approach to implement JavaScript inheritance - a "lazy" inheritance which has all benefits of prototype-based inheritance like typed classes,but also eliminates necessity to declare external scripts in proper order and automatically resolves and loads (if necessary) dependencies to
external scripts that contains related classes.

You can find more about it on http://ajaxline.com/node/367
I'll glad to get any comments from you.