I realize that Javascript does not have classes and is not built to have classical OOP inheritance. But I find such patterns so useful that I wanted to build a simple way to model that kind of behavior, ideally while leveraging the best parts of Javascript's flexibility. What are the pros and cons of the following approach?
I have the following functions in my custom library:
function inherit(superClass, args, instance) {
var subClass = inherit.caller;
var o = new superClass(args);
for(p in o) {
if(o.hasOwnProperty(p)) init(instance, p, o[p]);
else init(subClass.prototype, p, o[p]);
}
}
function isUndefined(x) {var u; return x === u;}
// sets p to value only if o[p] is undefined
function init(o, p, value) {if(isUndefined(o[p])) o[p] = value;}
This setup requires two conventions:
- Functions that are modelling classes must take one argument: an object with named properties
- Functions wishing to "inherit" from another must call the inherit function.
Here's an example of what you get as a result (paste into the Firebug mand line, along with the library functions, to see it in action):
function SuperClass(args) {
this.x = args.x;
}
SuperClass.prototype.p = 'SuperClass prototype property p';
function SubClass(args) {
inherit(SuperClass, args, this);
this.y = args.y;
}
SubClass.prototype.q = 'SubClass prototype property q';
var o = new SubClass({
x: 'x set in SuperClass',
y: 'y set in SubClass'
});
console.dir(o); // correctly has properties x, y, p, and q
['x', 'y', 'p', 'q'].forEach(function(prop) {
// true for x and y, false for p and q
console.log("o.hasOwnProperty('" + prop + "')", o.hasOwnProperty(prop));
});
console.log("o instanceof SubClass: ", o instanceof SubClass); // true
console.log("o instanceof SuperClass: ", o instanceof SuperClass); // false
I am aware of the following cons:
- Modifying the super class prototype will not affect your instance object, as you might expect from prototype-style inheritance
- The instance object will not register as instanceof the super class (although it will still quack like one)
- The argument conventions might be annoying
and pros:
- Requires only one function call (easy to implement)
- Differentiates between prototype properties and instance properties
- Arguments passed to the sub class are also passed to the super class
- Instance properties set by the super class constructor are immediately available in the sub class constructor
- Multiple inheritance is easy, just call inherit multiple times in your sub class
- Doesn't over-write existing properties of the sub class
Pros 3 - 6 specifically make this method more useful for me than the SubClass.prototype = new SuperClass()
method. Other methods, like dojo's class modelling, are much more plicated, I think unnecessarily so.
So, tell me what you think. And if someone else has done this before, please let me know, I haven't intended to duplicate any ideas.
I realize that Javascript does not have classes and is not built to have classical OOP inheritance. But I find such patterns so useful that I wanted to build a simple way to model that kind of behavior, ideally while leveraging the best parts of Javascript's flexibility. What are the pros and cons of the following approach?
I have the following functions in my custom library:
function inherit(superClass, args, instance) {
var subClass = inherit.caller;
var o = new superClass(args);
for(p in o) {
if(o.hasOwnProperty(p)) init(instance, p, o[p]);
else init(subClass.prototype, p, o[p]);
}
}
function isUndefined(x) {var u; return x === u;}
// sets p to value only if o[p] is undefined
function init(o, p, value) {if(isUndefined(o[p])) o[p] = value;}
This setup requires two conventions:
- Functions that are modelling classes must take one argument: an object with named properties
- Functions wishing to "inherit" from another must call the inherit function.
Here's an example of what you get as a result (paste into the Firebug mand line, along with the library functions, to see it in action):
function SuperClass(args) {
this.x = args.x;
}
SuperClass.prototype.p = 'SuperClass prototype property p';
function SubClass(args) {
inherit(SuperClass, args, this);
this.y = args.y;
}
SubClass.prototype.q = 'SubClass prototype property q';
var o = new SubClass({
x: 'x set in SuperClass',
y: 'y set in SubClass'
});
console.dir(o); // correctly has properties x, y, p, and q
['x', 'y', 'p', 'q'].forEach(function(prop) {
// true for x and y, false for p and q
console.log("o.hasOwnProperty('" + prop + "')", o.hasOwnProperty(prop));
});
console.log("o instanceof SubClass: ", o instanceof SubClass); // true
console.log("o instanceof SuperClass: ", o instanceof SuperClass); // false
I am aware of the following cons:
- Modifying the super class prototype will not affect your instance object, as you might expect from prototype-style inheritance
- The instance object will not register as instanceof the super class (although it will still quack like one)
- The argument conventions might be annoying
and pros:
- Requires only one function call (easy to implement)
- Differentiates between prototype properties and instance properties
- Arguments passed to the sub class are also passed to the super class
- Instance properties set by the super class constructor are immediately available in the sub class constructor
- Multiple inheritance is easy, just call inherit multiple times in your sub class
- Doesn't over-write existing properties of the sub class
Pros 3 - 6 specifically make this method more useful for me than the SubClass.prototype = new SuperClass()
method. Other methods, like dojo's class modelling, are much more plicated, I think unnecessarily so.
So, tell me what you think. And if someone else has done this before, please let me know, I haven't intended to duplicate any ideas.
Share Improve this question edited Dec 28, 2011 at 15:52 Tom van der Woerdt 30k7 gold badges74 silver badges105 bronze badges asked Nov 3, 2010 at 15:02 ChrisChris 7,3083 gold badges37 silver badges51 bronze badges 2-
2
keep in mind that
caller
is non-standard and accessing it will throw an error in strict-mode ES5 – Christoph Commented Nov 3, 2010 at 16:00 - My favorite solution so far is coffeescript! jashkenas.github./coffee-script – Chris Commented Jan 17, 2011 at 16:31
3 Answers
Reset to default 4Those ing here to see simple and probably best way to do inheritance in javascript please read the following, its so much simpler than everything else I've scanned through:
http://javascript.crockford./prototypal.html
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
N.B: Object.create is now part of javascript in newer browsers, but by adding the above the following also works in older browsers.
newObject = Object.create(oldObject);
You might want to look at what John Resig has done with JavaScript inheritance: http://ejohn/blog/simple-javascript-inheritance/
It's the best attempt at Javascript inheritance that I've seen.
You know the cons of what you posted.... So take a look at my blog for a thorough explanation of what I think is the best way while describing the flaws of other patterns
http://js-bits.blogspot./2010/08/javascript-inheritance-done-right.html
Example:
//Abstraxct base class
function Animal(name) {
this.name = name;
}
Animal.prototype.sayMyName = function () {
console.log(this.getWordsToSay() + " " + this.name);
}
Animal.prototype.getWordsToSay = function () {} // abstract
// --------------------------------
function Dog(name) {
// Call the parent's constructor
Animal.call(this, name);
}
extend(Dog, Animal, {
getWordsToSay: function(){
return "Ruff Ruff";
}
});
The code I posted is an example syntax. The blog posts goes into details about how to add syntactic sugar.
The important things are:
- new Dog("Lassie") instanceof Animal // true
- The Animal constructor is not called just to setup inheritance
- var dog = new Dog("Lassie"); Animal.prototype.blah = 5; dog.blah == 5; //outputs true