Enhanced Class Inheritance with JavaScriptMVC
Date : 2008 06 16 Category : Tech & DevelopmentBrian Moschel from the JavaScriptMVC project wrote in to tell us about their recent efforts extending John Resig's earlier Simple Class Inheritance work.
In case you missed it, John's blog talked about his efforts to take the best of the many efforts to simulate classical inheritance in JavaScript and reduce them to a simple, easy-to-use piece of stand-alone JavaScript. Here's an example of the syntax he settled on:
PLAIN TEXT JAVASCRIPT:var Person = Class.extend({ init: function(isDancing){ this.dancing = isDancing; }, dance: function(){ return this.dancing; } }); var Ninja = Person.extend({ init: function(){ this._super( false ); }, dance: function(){ // Call the inherited version of dance() return this._super(); }, swingSword: function(){ return true; } }); var p = new Person(true); p.dance(); // => true var n = new Ninja(); n.dance(); // => false n.swingSword(); // => true // Should all be true p instanceof Person && p instanceof Class && n instanceof Ninja && n instanceof Person && n instanceof Class
The JavaScriptMVC guys built on top of his work to add:
Class level inheritance: Easily reuse functionality by inheriting class methods and using superclass methods the same way as instance methods Class initialization callbacks: Setup your classes and keep track of subclasses with callback functions invoked once during class initialization Introspection: Allow classes to behave differently based on the name of the class, similar to ActiveRecord Access to the instance's class and superclass: Write code that directly accesses class methods and objects from instance methods even when you don’t know the name of the classTheir stuff will be available as a plugin to JavaScriptMVC at some point in the future, but is available now as standalone JavaScript.
Here's a code sample of these new features at work:
PLAIN TEXT JAVASCRIPT:Class.extend(‘monster’, // class methods { find: function(name){ return this.creatures[name]; }, // called whenever Monster is subclassed extended: function(Class){ this.types.push(Class.className); }, types: [], creatures: {} }, // prototype methods { // constructor init: function(name){ this.name = name; this.life = 100; this.attack_stength = 20; this.Class.creatures[name] = this; }, attack: function(creature){ creature.life -= this.attack_stength; } }); Monster.extend(’sea_monster’); Monster.extend(‘dragon’,{ find: function(name){ var found = this._super(name); // Dragons’ spirits are raised when they feel wanted found.life+=10; return found; } },{ init: function(name){ // call the inherited version of init() this._super(name); this.attack_stength = 50; }, attack: function(creature){ // dragons hurt themselves a bit when they attack this.life -= 5; // call the inherited version of attack this._super(creature); } }) Monster.types; // => [’sea_monster’,'dragon’] var h = new Monster(‘hydra’); var a = new Dragon(‘albi’); a.attack_stength; // 50 a.Class.className; // ‘dragon’ a.attack(h); // h.life = 50, a.life = 95 var d = Dragon.find(‘albi’); // returns albi instance, d.life = 105