Chris
Chris

Reputation: 7288

Pros and cons of inheritance modeling in Javascript?

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:

  1. Functions that are modelling classes must take one argument: an object with named properties
  2. 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 command 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:

  1. Modifying the super class prototype will not affect your instance object, as you might expect from prototype-style inheritance
  2. The instance object will not register as instanceof the super class (although it will still quack like one)
  3. The argument conventions might be annoying

and pros:

  1. Requires only one function call (easy to implement)
  2. Differentiates between prototype properties and instance properties
  3. Arguments passed to the sub class are also passed to the super class
  4. Instance properties set by the super class constructor are immediately available in the sub class constructor
  5. Multiple inheritance is easy, just call inherit multiple times in your sub class
  6. 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 complicated, 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.

Upvotes: 9

Views: 2292

Answers (3)

Darren
Darren

Reputation: 9499

Those coming 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.com/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);

Upvotes: 4

Ruan Mendes
Ruan Mendes

Reputation: 92274

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.com/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

Upvotes: 0

brendan
brendan

Reputation: 29986

You might want to look at what John Resig has done with JavaScript inheritance: http://ejohn.org/blog/simple-javascript-inheritance/

It's the best attempt at Javascript inheritance that I've seen.

Upvotes: 3

Related Questions