継承の再考

JavaScript の継承およびコンストラクタのプロトタイプの説明については、継承とコンストラクタのプロトタイプをご覧ください。

JavaScript では継承が常に使用可能ですが、このページの例では ECMAScript 5 で導入されたメソッドをいくつか使用します。それらがエミュレート可能であるかについては、各メソッド個別のページをご覧ください。

BA から継承するでしょう:

function A(a){
  this.varA = a;
}
A.prototype = {
  varA : null,
  doSomething : function(){
    // ...
  }
}
function B(a, b){
  A.call(this, a);
  this.varB = b;
}
B.prototype = Object.create(new A(), {
  varB : { value: null, enumerable: true, configurable: true, writable: true },
  doSomething : { value: function(){ // オーバーライド
       A.prototype.doSomething.apply(this, arguments); // 上位の呼び出し
       // ...
    }, enumerable: true, configurable: true, writable: true }
})

var b = new B();
b.doSomething();

ここでは以下の点が重要です:

  • 型は .prototype で定義されます。
  • 継承するために Object.create() を使用します。

prototype と Object.getPrototypeOf

Java や C++ を経験してきた開発者にとって JavaScript は、すべてが動的であり、すべてが実行時に決まり、そしてクラスがまったく存在しないことから、ややわかりにくい言語です。JavaScript では単純に、すべてがインスタンス (オブジェクト) です。"クラス" をシミュレートしているものでさえ、単なる関数オブジェクトです。

すでに気づいているかもしれませんが、function Aprototype と呼ばれる特別なプロパティを持っています。この特別なプロパティは、JavaScript の new とともに働きます。プロトタイプオブジェクトへの参照は、新たなインスタンスの内部にある [[Prototype]] プロパティにコピーされます。例えば var a1 = new A() という処理を行うとき、JavaScript は (オブジェクトをメモリ内に作成した後、かつそのオブジェクトを this に定義して A() を実行する前) に a1.[[Prototype]] = A.prototype をセットします。そしてインスタンスのプロパティにアクセスするとき、JavaScript はまず、オブジェクト上にそれらが直接存在しているかを確認します。存在しない場合は、[[Prototype]] を参照します。これは prototype で定義したすべての内容が、すべてのインスタンスで効率的に共有されることを意味します。また、必要に応じて prototype の一部を後から変更したり、その変更を存在する全インスタンスに反映させることもできます。

前出の例で var a1 = new A(); var a2 = new A(); を実行したとき、a1.doSomething は実際は Object.getPrototypeOf(a1).doSomething を参照しており、これは A.prototype.doSomething と同じです。すなわち、Object.getPrototypeOf(a1).doSomething == Object.getPrototypeOf(a2).doSomething == A.prototype.doSomething です。

簡潔に言うと、prototype は型のためのものであり、一方 Object.getPrototypeOf() はインスタンスと同じです。

[[Prototype]]再帰的に参照されます。すなわち a1.doSomethingObject.getPrototypeOf(a1).doSomethingObject.getPrototypeOf(Object.getPrototypeOf(a1)).doSomething というように、doSomething が見つかるか Object.getPrototypeOf が null を返すまで続けます。

よって、次のように呼び出したとき:

var o = new Foo();

JavaScript は、実際には以下のように実行します:

var o = new Object();
o.[[Prototype]] = Foo.prototype;
o.Foo();

(あるいは類似の何らかの処理を行います) また、その後以下の処理を行うとき:

o.someProp;

JavaScript は osomeProp を持っているかを確認します。持っていない場合は Object.getPrototypeOf(o).someProp を確認し、ここにも存在しない場合は Object.getPrototypeOf(Object.getPrototypeOf(o)).someProp を確認、などというように動作します。

ドキュメントのタグと貢献者

最終更新者: yyss,