Search code examples
javascriptoopinheritanceprototypal-inheritance

Is John Resig's Javascript inheritance snippet deprecated?


I'm looking for a simple way of creating two classes, one inheriting from the other, and the child redefining one of the parent's methods, and inside the new method, calling the parent's.

For example, having a class Animal and Dog, where the Animal class defines a method makeSound() which establishes how to output a sound, which Dog then overrides in its own makeSound() method to make a "woof" sound, but while also calling Animal's makeSound() to output that woof.

I looked at John Resig's model here, but it uses the native arguments.callee property which is apparently depreciated in ECMA script 5. Does that mean I shouldn't use John Resig's code?

What would one neat, simple way of writing my animal/dog code using Javascript's prototype inheritance model?


Solution

  • Does that mean I shouldn't use John Resig's code?

    Correct, not when you are using ES5 in strict mode. However, it can be easily adapted:

    /* Simple JavaScript Inheritance for ES 5.1
     * based on http://ejohn.org/blog/simple-javascript-inheritance/
     *  (inspired by base2 and Prototype)
     * MIT Licensed.
     */
    (function(global) {
      "use strict";
      var fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
    
      // The base Class implementation (does nothing)
      function BaseClass(){}
    
      // Create a new Class that inherits from this class
      BaseClass.extend = function(props) {
        var _super = this.prototype;
    
        // Set up the prototype to inherit from the base class
        // (but without running the init constructor)
        var proto = Object.create(_super);
    
        // Copy the properties over onto the new prototype
        for (var name in props) {
          // Check if we're overwriting an existing function
          proto[name] = typeof props[name] === "function" && 
            typeof _super[name] == "function" && fnTest.test(props[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, props[name])
            : props[name];
        }
    
        // The new constructor
        var newClass = typeof proto.init === "function"
          ? proto.hasOwnProperty("init")
            ? proto.init // All construction is actually done in the init method
            : function SubClass(){ _super.init.apply(this, arguments); }
          : function EmptyClass(){};
    
        // Populate our constructed prototype object
        newClass.prototype = proto;
    
        // Enforce the constructor to be what we expect
        proto.constructor = newClass;
    
        // And make this class extendable
        newClass.extend = BaseClass.extend;
    
        return newClass;
      };
    
      // export
      global.Class = BaseClass;
    })(this);