goog.inherit Vs. simple inherit

JavaScript performance comparison

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;
  
  };
  
  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)
    }
  });

};
</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…

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