5

In this snippet of Google Closure javascript code involving a constructor, why is goog.base(this); necessary? Doesn't Foo already inherit from Disposable with goog.inherits(foo, goog.Disposable);?

goog.provide('Foo');

/**
 * @constructor
 * @extends {goog.Disposable}
 */
Foo = function() {
  goog.base(this);
}     
goog.inherits(foo, goog.Disposable);

foo.prototype.doSomething = function(){
  ...
}

foo.prototype.disposeInternal = function(){
  ...
}
Christopher Peisert
  • 21,862
  • 3
  • 86
  • 117
dangerChihuahua007
  • 20,299
  • 35
  • 117
  • 206

3 Answers3

9

goog.inherits(childConstructor, parentConstructor)

goog.inherits() establishes the prototype chain from the child constructor to the parent constructor.

/**
 * Inherit the prototype methods from one constructor into another.
 * @param {Function} childCtor Child class.
 * @param {Function} parentCtor Parent class.
 */
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;
};


In addition to prototype properties, constructors may have "own" properties (i.e. instance-specific properties added to this). Since goog.inherits() does not call the parent constructor, own properties are not copied to the child constructor and any initialization code in the parent does not get executed. For these reasons, the standard pattern is to chain constructors as in the following example.

/**
 * @param {string} name The parent's name.
 * @constructor
 */
var Parent = function(name) {
  /**
   * @type {string}
   * @private
   */
  this.name_ = name;
}

/**
 * @param {string} name The child's name.
 * @constructor
 * @extends {Parent}
 */
var Child = function(name) {
  Parent.call(this, name);
}
goog.inherits(Child, Parent);


goog.base(self, opt_methodName, var_args)

goog.base() is a helper function for calling parent methods so that you do not need to explicitly use call() or apply().

If [goog.base()] is called from a constructor, then this calls the superclass contructor with arguments 1-N.

If this is called from a prototype method, then you must pass the name of the method as the second argument to this function. If you do not, you will get a runtime error. This calls the superclass' method with arguments 2-N.

This function only works if you use goog.inherits to express inheritance relationships between your classes.

In Closure code it is common to chain constructors with goog.base() rather than calling the parent constructor explicitly.

/**
 * @param {string} name The child's name.
 * @constructor
 * @extends {Parent}
 */
var Child = function(name) {
  goog.base(this, name);
}
goog.inherits(Child, Parent);


Further Reading

Christopher Peisert
  • 21,862
  • 3
  • 86
  • 117
  • 1
    As somebody who is coming over from the `Java` world, would it make sense to say that `base` is to `inherits` as `super()` is to `extends`? – The111 Jul 09 '15 at 18:23
1

In JavaScript, this is set entirely by how the function is called, not where it's defined (as it is in Java, C#, and C++). So to make this within the call to goog.Disposable be the this of where you're calling it, you have to use .call or .apply. Otherwise, if you just called goog.Disposable(), within the call this would be goog.

Basically, there are two ways to set this for the function you're calling:

  1. Use obj.func() or obj["func"]() notation — e.g., make the call as part of the same overall expression where you're retrieving a property from the object. This tells the engine that within the call, you want this to refer to obj.

  2. Use call or apply to be more explicit about it by supplying the object to use as this as the first argument. The only difference between call and apply is how you supply other arguments: With call, you supply them as discrete args, e.g. foo.call(obj, 1, 2, 3) calls foo with this set to obj and the arguments 1, 2, and 3. With apply, you supply the arguments as an array-like second argument: foo.apply(obj, [1, 2, 3]); (note the [ and ]; e.g. var a = [1, 2, 3]; foo.call(obj, a);

More to explore:

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Can you make a canonical answer of this so we can use it as duplicate, I see you make this answer 100 times a day :D – Esailija Jun 20 '12 at 15:20
  • @Esailija: Yeah, it's *amazing* how many different contexts this comes up in. :-) Sometimes it's an outright duplicate, other times (like this one) it's *effectively* a duplicate but you can see why someone wouldn't have found an earlier answer... – T.J. Crowder Jun 20 '12 at 15:21
1

You can see

Foo = function() {
  goog.base(this); //call parent constructor
}     
goog.inherits(foo, goog.Disposable);

As:

public class Foo extends Disposable(){
  public Foo(){
    super(); // call parent constructor
  }
}
hguser
  • 35,079
  • 54
  • 159
  • 293