プロトタイプチェーンによる継承方法

暴露話から…。
私はここを参考にしてCPTの継承システムを作りました。
http://www.graviness.com/virgo/javascript/d020525.html
Virgo*1でこの記事をみて感服しました。

単なる「パクリ」ではもったいないし失礼だろうと思い、これを発展させてStaticについても継承させる作りにしました。


もともと、クラス(つまり、関数)所属のメンバやメソッドも継承させたかったのです。


// スーパークラス
function SuperClass() {
  return this;
}

SuperClass.prototype.protoMethod = function() {
  alert("SuperProto!");
};

// ↓これを継承させたい
SuperClass.classMethod = function() {
  alert("SuperClass!");
};

// サブクラス
function SubClass() {
  SuperClass.apply(this, arguments);
  return this;
}

// ここで継承(上記と全く同じ方法なので省略)

// これはできる
(new SubClass()).protoMethod();

// これがしたい
SubClass.classMethod();

しかし、ここで壁にぶち当たります。

SubClass.classMethodがプロトタイプチェーンでSuperClass.classMethodを参照するには、
SubClassのコンストラクタのprototypeSuperClassでなければなりません。
しかも、コンストラクタは内部的に持っているコンストラクタで、SubClass.constructorを付け替えても無駄でした。
そうすると、Function.prototypeSuperClassである必要があります。

考えた解決案とその結果は

  1. たった1つのクラス間継承のためにFunction.prototypeを付け替える。

    →そんなことはできません。
  2. SubClass.classMethodの実行中のみFunction.prototypeを付け替える。

    →そのためにはSubClass.classMethodそのものを作らなければならないので本末転倒。
  3. クラスは関数ではなくオブジェクトにする。

    newできなくなってしまう。(クラス名.create()でも可能だが、newしたい!!)
このようになりました。


そして最終的に導いた結論が、
「prototype」と同じようなプロトタイプチェーンで結ばれたオブジェクト*2をもう1つ作ってしまえばいい

でした。(これをCPTコアで実装しています。ソースを見ればすぐ発見できると思います。)


※ちなみにprototype.jsはプロトタイプチェーンを使った継承ではない・・・と、同じように考えている方もいるようですね。
http://d.hatena.ne.jp/amachang/20060227

06/03/21追記
どうやら私はprototype.jsを少しばかり誤解していたようです。
prototype.jsの継承メソッド


Object.extend = function(destination, source) {
  for (property in source) {
    destination[property] = source[property];
  }
  return destination;
}
を見て、「なんだ、浅いコピーしちゃってるじゃん」と思いましたが、このメソッドを呼ぶ側でnewしてから使うわけですね。*3
また、継承じゃなくて単にメンバを追加するときはnewせずに使う・・・ということでしょうか。
なるほど、そう使うのか。

*1:GRAVINESS.COM

*2:CPTではクラス名.Staticとなります。

*3:参考:http://d.hatena.ne.jp/reinyannyan/20060320