goog.inherit Vs. simple inherit

JavaScript performance comparison

Revision 2 of this test case created by Benny Bennet

Preparation code


      
      <script>
Benchmark.prototype.setup = function() {
  var goog = {};
  goog.inherits = function(childCtor, parentCtor) { /** @constructor */
  
    function tempCtor() {};
    tempCtor.prototype = parentCtor.prototype;
    childCtor.superClass_ = parentCtor.prototype;
    childCtor.prototype = new tempCtor(); /** @override */
    childCtor.prototype.constructor = childCtor;
  };
  goog.base = function(me, opt_methodName, var_args) {
    var caller = arguments.callee.caller;
    if (caller.superClass_) {
      // This is a constructor. Call the superclass constructor.
      return caller.superClass_.constructor.apply(
      me, Array.prototype.slice.call(arguments, 1));
    }
  
    var args = Array.prototype.slice.call(arguments, 2);
    var foundCaller = false;
    for (var ctor = me.constructor;
    ctor; ctor = ctor.superClass_ && ctor.superClass_.constructor) {
      if (ctor.prototype[opt_methodName] === caller) {
        foundCaller = true;
      } else if (foundCaller) {
        return ctor.prototype[opt_methodName].apply(me, args);
      }
    }
  
    // If we did not find the caller in the prototype chain,
    // then one of two things happened:
    // 1) The caller is an instance method.
    // 2) This method was not called by the right caller.
    if (me[opt_methodName] === caller) {
      return me.constructor.prototype[opt_methodName].apply(me, args);
    } else {
      throw Error('goog.base called from a method of one name ' + 'to a method of a different name');
    }
  };
  
  var fnTest = /xyz/.test(function() {
    xyz;
  }) ? /\b_super\b/ : /.*/;
  
  Class = function() {};
  Class.extend = function extend(prop) {
    var _super = this.prototype;
  
    function Child() {
      if (this.init) this.init.apply(this, arguments);
    }
    Child.prototype = Object.create(this.prototype);
    Child.prototype.constructor = Child;
    Child.extend = extend;
  
    for (var name in prop) {
      // Check if we're overwriting an existing function
      if (typeof prop[name] == "function" && typeof _super[name] == "function" && /\b_super\b/.test(prop[name])) {
        Child.prototype[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]);
      } else {
        Child.prototype[name] = prop[name];
      }
    }
    return Child;
  }
  
  
  ClassJR = function() {};
  
  // Create a new Class that inherits from this class
  ClassJR.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;
  };
  
  ClassSG = function() {};
  
  
  
  // Create a new Class that inherits from this class
  ClassSG.extend = function(prop) {
  
    var _super = this.prototype;
  
  
  
    // Instantiate a base class (but only create the instance,
    // don't run the init constructor)
    var Surrogate = function() {
        this.constructor = {};
        };
  
    Surrogate.prototype = this.prototype;
  
    prototype = new Surrogate;
  
  
  
    // 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 (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;
  
  };
  
  BBClass = function( ctor ) {
  
          ctor.prototype = Object.create({});
          ctor.extend = function( parent ) {
              function ChildBB() { parent.prototype.constructor(); ctor.call(this); };
              ChildBB.prototype = (typeof Object.create !== 'function') ?
                  (function (parent) { function F() {}; F.prototype = parent.prototype; return new F(); })( parent )
                  : Object.create(parent.prototype);
              ChildBB.prototype.constructor =  ChildBB;
              return ChildBB;
          }
          ctor.prototype.constructor = ctor;
          return ctor;
      };
  
  var googA = function() {
      this.a = 'a';
      this.b = 'b';
      this.c = this.a + this.b;
      };
  googA.prototype.foo = function() {
    return "foo"
  };
  googA.prototype.hello = function() {
    return "hello";
  };
  googA.prototype.foobar = function() {
    return "foobar";
  };
  googA.prototype.foobar2 = function() {
    return "foobar2";
  };
  
  var googB = function() {
      googA.call(this);
      };
  goog.inherits(googB, googA);
  googB.prototype.foo = function() {
    return googA.prototype.foo.call(this);
  };
  googB.prototype.bar = function() {
    return "bar";
  };
  googB.prototype.foobar = function() {
    return googB.superClass_.foobar.call(this);
  };
  googB.prototype.foobar2 = function() {
    return googA.prototype.foobar2.call(this);
  };
  
  var extendA = Class.extend({
    init: function() {
      //this is constructor
      this.a = 'a';
      this.b = 'b';
      this.c = this.a + this.b;
    },
    foo: function() {
      return "foo";
    },
    hello: function() {
      return "hello";
    },
    foobar: function() {
      return "foobar";
    }
  });
  
  var extendB = extendA.extend({
    init: function() {
      this._super();
    },
    foo: function() {
      this._super();
    },
    bar: function() {
      return "bar";
    },
    foobar: function() {
      return extendA.prototype.foobar.call(this)
    }
  });
  
  var extendJRA = ClassJR.extend({
    init: function() {
      //this is constructor
      this.a = 'a';
      this.b = 'b';
      this.c = this.a + this.b;
    },
    foo: function() {
      return "foo";
    },
    hello: function() {
      return "hello";
    },
    foobar: function() {
      return "foobar";
    }
  });
  
  var extendJRB = extendJRA.extend({
    init: function() {
      this._super();
    },
    foo: function() {
      this._super();
    },
    bar: function() {
      return "bar";
    },
    foobar: function() {
      return extendJRA.prototype.foobar.call(this)
    }
  });
  
  var extendSGA = ClassSG.extend({
    init: function() {
      //this is constructor
      this.a = 'a';
      this.b = 'b';
      this.c = this.a + this.b;
    },
    foo: function() {
      return "foo";
    },
    hello: function() {
      return "hello";
    },
    foobar: function() {
      return "foobar";
    }
  });
  
  var extendSGB = extendSGA.extend({
    init: function() {
      this._super();
    },
    foo: function() {
      this._super();
    },
    bar: function() {
      return "bar";
    },
    foobar: function() {
      return extendSGA.prototype.foobar.call(this)
    }
  });
  
  var bbClassA = BBClass(function() {
    //this is constructor
    this.a = 'a';
    this.b = 'b';
    this.c = this.a + this.b;
  });
  bbClassA.prototype = {
    foo: function() {
      return "foo";
    },
    hello: function() {
      return "hello";
    },
    foobar: function() {
      return "foobar";
    }
  };
  
  var bbClassB = BBClass(function() {}).extend(bbClassA);
  bbClassB.prototype = {
    foo: function() {
      this._super();
    },
    bar: function() {
      return "bar";
    },
    foobar: function() {
      return extendSGA.prototype.foobar.call(this)
    }
  };

};
</script>

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in CCBot 2.0.0 / Other 0.0.0
Test Ops/sec
1.1 goog.inherit define classes
var googA = function() {
    this.a = 'a';
    this.b = 'b';
    this.c = this.a + this.b;
    };
googA.prototype.foo = function() {
  return "foo"
};
googA.prototype.hello = function() {
  return "hello";
};
googA.prototype.foobar = function() {
  return "foobar";
};
googA.prototype.foobar2 = function() {
  return "foobar2";
};

var googB = function() {
    googA.call(this);
    };
goog.inherits(googB, googA);
googB.prototype.foo = function() {
  return googA.prototype.foo.call(this);
};
googB.prototype.bar = function() {
  return "bar";
};
googB.prototype.foobar = function() {
  return googB.superClass_.foobar.call(this);
};
googB.prototype.foobar2 = function() {
  return googA.prototype.foobar2.call(this);
};
pending…
1.2 Extend define classes
var extendA = Class.extend({
  init: function() {
    //this is constructor
    this.a = 'a';
    this.b = 'b';
    this.c = this.a + this.b;
  },
  foo: function() {
    return "foo";
  },
  hello: function() {
    return "hello";
  },
  foobar: function() {
    return "foobar";
  }
});

var extendB = extendA.extend({
  init: function() {
    this._super();
  },
  foo: function() {
    this._super();
  },
  bar: function() {
    return "bar";
  },
  foobar: function() {
    return extendA.prototype.foobar.call(this)
  }
});
pending…
1.3 John Resig Extend define classes
var extendJRA = ClassJR.extend({
  init: function() {
    //this is constructor
    this.a = 'a';
    this.b = 'b';
    this.c = this.a + this.b;
  },
  foo: function() {
    return "foo";
  },
  hello: function() {
    return "hello";
  },
  foobar: function() {
    return "foobar";
  }
});

var extendJRB = extendJRA.extend({
  init: function() {
    this._super();
  },
  foo: function() {
    this._super();
  },
  bar: function() {
    return "bar";
  },
  foobar: function() {
    return extendJRA.prototype.foobar.call(this)
  }
});
pending…
1.4 Surrogate Extend define
var extendSGA = ClassSG.extend({
  init: function() {
    //this is constructor
    this.a = 'a';
    this.b = 'b';
    this.c = this.a + this.b;
  },
  foo: function() {
    return "foo";
  },
  hello: function() {
    return "hello";
  },
  foobar: function() {
    return "foobar";
  }
});

var extendSGB = extendSGA.extend({
  init: function() {
    this._super();
  },
  foo: function() {
    this._super();
  },
  bar: function() {
    return "bar";
  },
  foobar: function() {
    return extendSGA.prototype.foobar.call(this)
  }
});
pending…
2.1 Goog inherit object creation
var GA = new googA();
var GB = new googB();
pending…
2.2 Extend object creation
var EA = new extendA();
var EB = new extendB();
pending…
2.3 JR Extend object creation
var EJRA = new extendJRA();
var EJRB = new extendJRB();
pending…
2.4 Surrogate object creation
var ESGA = new extendSGA();
var ESGB = new extendSGB();
pending…
1.5 bennybennet define class
var bbClassA = BBClass(function() {
  //this is constructor
  this.a = 'a';
  this.b = 'b';
  this.c = this.a + this.b;
});
bbClassA.prototype = {
  foo: function() {
    return "foo";
  },
  hello: function() {
    return "hello";
  },
  foobar: function() {
    return "foobar";
  }
};

var bbClassB = BBClass(function() {}).extend(bbClassA);
bbClassB.prototype = {
  foo: function() {
    this._super();
  },
  bar: function() {
    return "bar";
  },
  foobar: function() {
    return extendSGA.prototype.foobar.call(this)
  }
};
pending…
2.5 bennybennet object creation
var BBA = new bbClassA();
var BBB = new bbClassB();
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL.

0 Comments