Inheritance in Javascript (one way)
So, I recently posted a tip on how I write classes. So someone asked me how I use inheritance there. Well, one of the functions that I really like comes from the ACE source. You can look at it here. I'm going to paste an excerpt of the function too:
/* From the ACE Source code
Distributed under the BSD license:
Copyright (c) 2010, Ajax.org B.V.
All rights reserved.
*/
exports.inherits = (function() {
var tempCtor = function() {};
return function(ctor, superCtor) {
tempCtor.prototype = superCtor.prototype;
ctor.super_ = superCtor.prototype;
ctor.prototype = new tempCtor();
ctor.prototype.constructor = ctor;
};
}());
When I use this particular method, here's the flow:
var Base = function() {
};
(function() {
this.method = function method() {
return 'BASE';
}
}).call(Base.prototype);
The derived class then:
var Derived = function() {
};
oop.inherits(Derived, Base);
(function() {
}).call(Derived.prototype);
Now, I have to do this between the constructor and the prototype definition because if you look at the inherits code, you'll see that it completely overrides the prototype. Therefore, I just let the inheritance method copy the base class' prototype, and then go ahead and modify it on my own. Here's another strong point with writing classes the way I do, I'm just modifying the prototype, not re-writing it from scratch. However, the big caveat here is that if you want to use the super class method, you'd have to do something like this within a method:
Derived.super_.method.call(this);
I don't have problems with this, but don't like the way I have to mention the class name every time to call the parent method. It's a little more verbose than I like. Though, it definitely works. No issues there.
Ok. Now the other big method I really like is written here by John Resig (the guy who made jQuery). It's an excellent article to read if you ever want to brush up/ learn about inheritance in javascript.
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* 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;
// 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;
};
})();
Read through the comments and you'll get a pretty good idea what's going on here. Though there is one problem here. He's written the code thinking we'll all go around deriving from a base class and writing code like this:
var Person = Class.extend({
init: function(isDancing){
this.dancing = isDancing;
}
});
var Ninja = Person.extend({
init: function(){
this._super( false );
}
});
var p = new Person(true);
p.dancing; // => true
var n = new Ninja();
n.dancing; // => false
Not that there's anything wrong with the above, I just don't want to have to do this to get inheritance working. So, I messed around and merged the two methods into something I like.
/* JavaScript Inheritance
* Author: Mutahhir Ali Hayat
* Made by joining some parts by John Resig http://ejohn.org/ and some by Ajax.org Code Editor (ACE)
*/
define(function(require, exports, module) {
var initializing = false,
fnTest = /xyz/.test(function() {
xyz;
}) ? /\b_super\b/: /.*/;
exports.inherits = (function() {
var tempCtor = function() {};
return function(ctor, superCtor) {
tempCtor.prototype= superCtor.prototype;
var prop = ctor.prototype,
_super = superCtor.prototype,
prototype = new tempCtor();
for(var name in prop) {
prototype[name] =
typeof prop[name] === "function" &&
typeof _super[name] === "function" &&
fnTest.test(prop[name])?
(function(name, fn){
return function(){
var tmp = this._super;
this._super = _super[name];
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
}
})(name, prop[name]) : prop[name];
}
ctor.prototype = prototype;
ctor.prototype.constructor = ctor;
return ctor;
}
})();
});
How you use it is mentioned in the Gist I created (forgot I wasn't signed in, and it didn't ask me, so Anonymously posted :))
Basically... the major change is that instead of sandwiching the inheritance call between the constructor and prototype definition, you have to do something like this:
var Derived = function() {
}
(function() {
}).call(Derived.prototype);
inherits(Derived, Base);Written by Mutahhir
Related protips
Have a fresh tip? Share with Coderwall community!
JavaScript on a page runs with the privileges of that origin. One altered library, tag manager, or snippet can read inputs, change what people see, and call your APIs as the user.
Security insights from Cside