DeLLa.JS #5行ってきたよ

そんな訳で寝坊して1時間ぐらい遅刻してDeLLa.JS #5に参加してきました。会場は[http:/www.vish.co.jp/:title=VISH株式会社さん]。

今回はP.158 9.3から9章終わりまでのClassやらmix-inやらについてを読み進めました。実は今回の読書範囲は、1年ぐらい前にサイ本を買った時に熟読していて、結構研究していたところだったりします。

まず書かないといけない事が…。今回読書した範囲に記載されている部分に記載されているサンプルはあまり参考にしない方が良いと思います。

  • 継承とかのあたりは世間でかなり研究/ハックされてきており、原著の執筆時点よりも洗練されたパターンが現在は存在している。
    • prototype.jsのClass.create()を参考にした方が良いと思う。
  • typeOf()の実装は実際には使えないケースが多々あると思うので、積極的には使っていくことができない。実装アイデア自体もあまり良い発想とは思えない。
  • ダックタイピングというわりにチェックが厳密すぎやしないか?

会場でも話が出ましたが、今回の読書範囲のサンプルは陳腐化しているところが多く、Javaみたいな言語に無理やり合わせようとしている面が強く感じられ、正直どうよ?って感じが強くします。

なので、サイ本に書いてある内容をちょっと超えてまとめると…。

  • 厳密にいえば、JavaScriptにはClassは存在しない。
    • ハックするとClassっぽいものは作れる/書ける。
      • (前述してるけど)prototype.jsのClass.create()を参考にするといいよ。
  • Javaなどの言語でいうところのsuperは存在しないし、あまり上手い実装方法も(ワタシが知っている範囲では)存在しない。
    • オーバーライドしたけど親のメソッドを参照したいような場合、「親のプロトタイプのfunctionをapply/callする」か、もしくは「オーバーライドする前にメソッド名に「_」とかを付与してコピーしておく」とかして逃げる事が多い。
  • ダックタイピングは良く使うが、現実的には「プロパティ/メソッドが存在するか否か」か「存在した場合、型が正しいか」程度の判定で実用十分ではないか。

文章だけで書いても判りづらい気がするので、superの代替方法とダックタイピングの例を書いておきます。

superの代替方法

親のプロトタイプのfunctionをapply/callする例。子の側で親のクラス名を明示的に指定しないといけない欠点はある。

// 親クラス
var Klass = function() {};
Klass.prototype.hoge = function() { return "hoge" };

// 子クラス
var SubKlass = function() {};
SubKlass.prototype = new Klass();
SubKlass.prototype.constructor = SubKlass;

// hogeメソッドをオーバーライドしちゃう
SubKlass.prototype.hoge = function() {
    // 親のhogeをapply
    return Klass.prototype.hoge.apply(this,arguments);
};

次にオーバーライドする前にメソッド名に「_」とかを付与してコピーしておく例。

// 親クラス
var Klass = function() {};
Klass.prototype.hoge = function() { return "hoge" };

// 子クラス
var SubKlass = function() {};
SubKlass.prototype = new Klass();
SubKlass.prototype.constructor = SubKlass;

// hogeメソッドをオーバーライドする前に別名にコピー
SubKlass.prototype._hoge = SubKlass.prototype.hoge;
SubKlass.prototype.hoge = function() {
    return this._hoge();
}

ただし、別名コピーする場合、多重にオーバーライドする場合は命名に困る欠点があったりする。

// すでにKlassとSubKlassは定義済みだと…

// 孫クラス
var SubSubKlass = function() {};
SubSubKlass.prototype = new SubKlass();
SubSubKlass.prototype.constructor = SubSubKlass;

// こう書いちゃうと、SubKlassでせっかく作った別名が上書きされちゃう
SubSubKlass.prototype._hoge = SubKlass.prototype.hoge;

ダックタイピング

たとえばlengthプロパティの値を見てfor文でループさせてイテレータっぽいことする例。

function each(list,fn) {
    if (typeof(list.length) != number) return;
    for (var i = 0,len = list.length; i < len; i++) {
        fn(list[i],i);
    }
}

この例であれば、list.lengthがnumberであるかを判定すれば、大抵は大丈夫じゃないかと思う。