j6a_pa
Last Updated: February 25, 2016
·
1.093K
· mutahhir
2034643609a3d51207127b00dfacce5f

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);
Say Thanks
Respond