As John suggests, suppose that I have some code:
function Person(isDancing){
this.dancing = isDancing;
}
Person.prototype.dance = function(){
return this.dancing;
};
function Ninja(){
this.dancing = false;
}
Ninja.prototype.dance = function(){
return this.dancing;
};
Ninja.prototype.swingSword = function(){
return true;
};
That's normal JavaScript object code. Now, I decide to use John Resig's "Simple JavaScript Inheritance". John Resig suggests that I rewrite my code like this:
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;
}
});
Changes are in red. The implementations stay the same but the code syntax is different. It's a bit of a hassle if you have little bit of code and, for a lot of code, it's even more of a hassle.
Why can't I reuse my code as-is with only a few modifications? Something like this:
function Person(isDancing){
function Person(isDancing){
this.dancing = isDancing;
}
Person.prototype.dance = function(){
return this.dancing;
};
Person = Class.extend(Person);
function Ninja(){
this._super( false );
}
Ninja.prototype.dance = function(){
// Call the inherited version of dance()
return this._super();
};
Ninja.prototype.swingSword = function(){
return true;
};
Ninja = Person.extend(Ninja);
Ninja = Person.extend(Ninja);
I make this possible using a slight modification to John Resig's script. By checking to see if the argument passed to extend() is a function, instead of an object, the script can handle both syntaxes: John Resig's original syntax and the traditional JavaScript object syntax.
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* Init-by-function modification
* By Daniel Howard http://www.svexpertise.com/
* MIT Licensed.
*/
// Inspired by base2 and Prototype
(function(){
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function(){};
// Create a new Class that inherits from this class
Class.extend = function(prop) {
var _super = this.prototype;
if ( typeof prop == 'function' ) {
prop.prototype.init = prop;
for (var name in prop)
prop.prototype[name] = prop[name];
prop = prop.prototype;
}
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn){
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) :
prop[name];
}
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
if ( !initializing && this.init )
this.init.apply(this, arguments);
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
When a function is detected, instead of an object, the function is first saved to the init property. Then, all enumerable function properties (which will behave pretty much like static variables in classical class-based systems) are saved to the function's prototype object. Finally, and here's the magic pixie dust, the function's prototype object is used as the argument which the rest of the code generates the JavaScript class from. John Resig's code behaves the same but the function's prototype object becomes "the class object" instead of being directly passed as the original argument.
Person = Class.extend(Person);
...
Ninja = Person.extend(Ninja);
The extend() calls above take the JavaScript constructor functions and return the new JavaScript class. By assigning the return value to the function (variable), the new JavaScript class replaces the traditional JavaScript object creation function.
With this modification and technique, you can write traditional JavaScript object code and, if you later want to use John Resig's "Simple JavaScript Inheritance", you can add it with ease.
No comments:
Post a Comment