JavaScript 第5版 - 9章 クラスとコンストラクタとプロトタイプ(1)

JavaScript 第5版、「9章 クラスとコンストラクタとプロトタイプ」の「9.1 コンストラクタ」~「9.2 プロトタイプと継承」(151~158ページ)を読み進めていきます。

9.1 コンストラクタ

  • コンストラクタ関数は別のオブジェクトを返り値として返すことも可能で、その場合は返されたオブジェクトがnew式の値となる。thisの値であったオブジェクトは破棄される。

9.2 プロトタイプと継承

  • 全ての関数は、定義時にprototypeプロパティが生成され、その初期値はconstructorプロパティしか持たないオブジェクトになる。このconstructorプロパティが参照するのは関数自身である。
  • new演算子によって生成されたオブジェクトのプロトタイプは、コンストラクタ関数のprototypeプロパティの値になる。

9.2.1 継承プロパティへのアクセス

  • プロパティの値を読み出す場合、オブジェクト自身からプロパティを探し、見つからない場合にはプロトタイプオブジェクトをたどって探す。プロパティの値を書き込む場合はプロトタイプオブジェクトは使用されない。

9.2.2 組み込み型の拡張

  • 組み込みクラスのプロトタイプオブジェクトにも値を代入でき、これによって組み込みクラスそのものを拡張することができる。
  • Object.prototypeにプロパティを追加すると、(プロトタイプチェーンのせいで)空のオブジェクトに対しても追加したプロパティが調べられるようになる。オブジェクトを連想配列として利用するコードがうまく動かなくなるため、追加してはならない。

コンストラクタ関数のプロトタイプオブジェクトにプロパティを追加すると、そのコンストラクタ関数で初期化された全てのオブジェクト(インスタンス)でそのプロパティが使えるようになります。これは、インスタンスのスコープにプロパティが見つからない場合、プロトタイプオブジェクトをたどって、コンストラクタ関数のprototypeプロパティが参照されるためです(プロトタイプチェーン)。これによって、オブジェクト指向プログラミングにおける継承を実現することできます。

本章以降に関わる事柄について、本書の補足をしておくと、「プロトタイプ」や「プロトタイプオブジェクト」と呼ばれているものは、prototypeプロパティやprototypeプロパティが参照するオブジェクトとは別物です。一部の実装(FirefoxのSpiderMonkeyなど)では、内部的なプロパティである__proto__プロパティでオブジェクトのプロトタイプを参照できます(ECMAScriptでは、内部仕様としての内部プロパティの存在については説明されていますが、明確なプロパティとしては定義されていません)。プロトタイプチェーンは、prototypeオブジェクトをたどっていくのではなく、プロトタイプオブジェクトをたどっていくものです。

「プロトタイプ(オブジェクト)」が「prototype(オブジェクト)」と異なることは、次のようなコードを試してみるとわかります。

// Classクラスのコンストラクタ関数
function Class() {
}

// Class関数のprototypeオブジェクトにプロパティを追加
Class.prototype.method = function() { alert('Class.prototype.method'); };

// 「9.2 プロトタイプと継承」によると、
// new演算子で生成されたオブジェクトのプロトタイプは、コンストラクタ関数のprototypeプロパティの値になる。
// この例では、オブジェクトinstanceのプロトタイプは、
// constructorプロパティと追加したmethodプロパティを持つprototypeオブジェクトを参照するはずである。
var instance = new Class();

// プロトタイプチェーンをたどって、Class関数のprototypeオブジェクトが参照されていることがわかる。
alert(instance.constructor);  // Class関数オブジェクトが返される。
instance.method();  // 'Class.prototype.method'

// constructorもmethodも、instance自身のプロパティではないことがわかる。
alert(instance.hasOwnProperty('constructor'));  // 'false'
alert(instance.hasOwnProperty('method'));  // 'false'

// プロトタイプがprototypeとは別物であることがわかる。
alert(instance.prototype);  // 'undefined'
alert(instance.prototype === Class.prototype);  // 'false'
alert(instance.prototype.constructor);  // エラー
instance.prototype.method();  // エラー

// __proto__プロパティを持つ実装では、次のコードでも確認できる。
// alert(instance.__proto__);  // Class関数のprototypeオブジェクトが返される。
// alert(instance.__proto__ === Class.prototype);  // 'true'
// alert(instance.__proto__.constructor);  // Class関数オブジェクトが返される。
// instance.__proto__.method();  // 'Class.prototype.method'

コメント (0)

この記事へのコメントはまだありません。

コメントフォーム

トラックバック (0)

この記事へのトラックバックはまだありません。

この記事のトラックバックURI
http://dxd8.com/archives/81/trackback/
この記事のURI
http://dxd8.com/archives/81/