アプリキャストでは__proto__を使ってオブジェクトを継承する

あまり知られていませんが、JavaScriptでオブジェクトの継承関係を実現する最もスマートな方法は__proto__を使用する方法です。

クラスの継承は、Subclass.prototype.__proto__ = Superclass.prototype;というオマジナイを書けばOKです。

プログラマのためのJavaScript (11):継承についてもう少し - 檜山正幸のキマイラ飼育記 (はてなBlog)

一般的にはnewを使用する方法がよく知られていますが__proto__の方がより柔軟で副作用の少ない方法です(理由は上記引用元のサイトが詳しいです)。

ただこの方法は使用可能な環境が限定されてしまうため、クロスプラットフォームであることが重要な意味を持つブラウザのJavaScriptプログラミングでは、この手の継承が使われることはほとんどありません。

この方法は、__proto__プロパティの存在と操作可能性に頼ってます。しかし残念ながら、__proto__はECMAの標準ではなく、すべての環境で使えるものではありません。例えば、IEブラウザ環境ではダメです。

プログラマのためのJavaScript (11):継承についてもう少し - 檜山正幸のキマイラ飼育記 (はてなBlog)

また__proto__は次世代ECMAScriptでも標準化はされませんでした。残念ながら今後もブラウザ界隈で陽の目を見る可能性は少ないでしょう。

ECMAScript 3.1 では、(中略)プロトタイプの動的な代入は出来ないので、 __proto__ の全機能が使えるようになった訳ではありません。

次の JavaScript の仕様はこうなる! ECMAScript 3.0 から 3.1 への変更点まとめ - IT戦記


さて前置きが長くなりましたが、アプリキャストでの継承です。

アプリキャストは、__proto__への動的な代入が可能な上に、ブラウザのようにクロスプラットフォームを気にする必要はありません。アプリキャストでの継承には基本的には__proto__を使用するべきです。


aclib でも、__proto__を使用したクラスの継承を行っています。

// SliderをNodeから派生して作成する
Slider = function() { Node.apply(this, arguments); };
Slider.prototype = {
  __proto__: Node.prototype,
  ...
};

また組み込みオブジェクトの基底クラスの拡張も__proto__を使用します。

// 独自の基底クラスの定義
Hash = function() {};
Hash.prototype = { ... };

// 組み込みオブジェクトの先祖を、独自基底クラスに差し替える
Array.prototype.__proto__ = {
  __proto__: Hash.prototype,
  ...
};
Number.prototype.__proto__ = {
  __proto__: Hash.prototype,
  ...
}

基底クラスを拡張するために、Object.protoypeを直接変更してしまうと汚染が発生しますが、このように基底クラスを別途用意して差し込む方法であれば副作用はありません(これは__proto__の動的代入によりはじめて可能となる方法なので、クロスブラウザを標榜する巷のJavaScriptライブラリでは同様の設計は難しいでしょう)