yo_waka's blog

418 I'm a teapot

Google Closure Libraryの良いところ

Google Closure Libraryを使ってると、基本的にプロトタイプベースのOOPで書かざるを得なくなる訳ですが、その中でClosure Libraryを使ってクラスを書く上で最もベースとなっている"goog.inherits"と"goog.base"は改めてよくできてると思った。

goog.provide('foo.bar.Sample');

goog.require('goog.ui.Component');

/**
 * @constructor
 * @extends {goog.ui.Component}
 */
foo.bar.Sample = function() {
    goog.base(this);
};
goog.inherits(foo.bar.Sample, goog.ui.Component);

/**
 * @override
 */
foo.bar.Sample.prototype.createDom = function() {
  var el = goog.base(this, 'createDom');
  el.className = 'ui-sample';
  return el;
};

/**
 * On added to the DOM tree.
 * @override
 */
foo.bar.Sample.prototype.enterDocument = function() {
  goog.base(this, 'enterDocument');
  var el = this.getElement();
  this.getHandler().listen(el, 'mousedown', this.mouseDownHandler_, false, this);
};

/**
 * @param {goog.events.Event} evt
 * @private
 */
foo.bar.Sample.prototype.mouseDownHandler_ = function(evt) {
    console.log("Clicked sample");
};

こんな感じですごい自然にクラス継承したJSが書けるのが素晴らしいなーと。


goog.inheritsではいわゆるプロトタイプ継承やってるわけですが、多重継承するケースにも対応されています(といってもconstructorプロパティに自分自身を突っ込むだけだけど、こうしないと子孫クラスがみんな同じconstructorプロパティを見てしまう)。


goog.baseではgoog.inherits()でsuperClass_に指定されたクラスのプロトタイプから指定のメソッドを引いてきて、指定のコンテキストオブジェクトでもって実行してくれる。
メソッド指定なしだと、arguments.callee.caller.superClass_.constructor、つまり親クラスのコンストラクタを実行する。
EcmaScript5のStrictModeでは、arguments.calleeとarguments.caller使うと例外吐いてしまうので多分近いうちに中の実装は変わるんだろうけど。

function Child(arg1, arg2) {
    goog.base(this, arg1, arg2); // これは
    Parent.apply(this, Array.prototype.slice.call(arguments, 0)); // これと同じ
}
goog.inherits(Child, Parent);

/**
 * @override
 */
Child.prototype.someMethod = function(arg) {
    goog.base(this, 'someMethod', arg); // 親クラスのメソッドでargを処理してから
    // 独自の処理をごにょごにょ
};