JavaScriptのプロトタイプチェーンについてメモ

■ 目次

  1. 概要
  2. プロトタイプチェーンについて
  3. prototypeと__proto__について
  4. 参考

■ 概要

JavaScript勉強シリーズ

JavaScriptのプロトタイプチェーンについてメモ
↑以前プロトタイプ継承についてまとめたがその続きとしてプロトタイプチェーンという機能について調べる
プロトタイプ継承の記事から以下の前提をおさらいしておく

  • 全ての関数オブジェクトはprototypeという名前のプロパティを持つ
  • 関数オブジェクトのコンストラクタによって生成されたオブジェクトは全てprototypeオブジェクトへの(隠し)リンクを持つ

プロトタイプチェーンとはオブジェクトが他のオブジェクトのプロトタイプとなる連鎖のことを呼ぶ

prototypeオブジェクトを「親」と表現するとプロトタイプチェーンの動作として以下のようにプロパティを探す

  1. オブジェクト自身のプロパティ
  2. 1.のオブジェクトの「親」のオブジェクトのプロパティ(1で見つからなかったら)
  3. 2.のオブジェクトの「親」のオブジェクトのプロパティ(2で見つからなかったら)
  4. 探索が終わるまで繰り返す (「親」の終端に当たるのはObject.prototype)

「親」の終端がObject.prototypeであることを確認するための例

// クラス相当定義
// (JavaScriptにはクラスを作成する機能はないが便宜上クラスと呼ぶ)
function TestClass(){return;}

// コンストラクタ呼び出し
// TestClassインスタンスの作成
var obj = new TestClass();

// objの親オブジェクトはTestClass.prototypeである
// つまりobjはTestClass.prototypeを継承している
obj.__proto__ === TestClass.prototype; // true

// objの親の親オブジェクトはObject.prototypeである
// つまりobjやTestClass.prototypeはObject.prototypeを継承している
obj.__proto__.__proto__ === Object.prototype; // true

プロトタイプチェーンによってプロパティが連鎖していることを確認する例

// クラス相当定義
// (JavaScriptにはクラスを作成する機能はないが便宜上クラスと呼ぶ)
function TestClass(){return;}

TestClass.prototype.x = 3;
Object.prototype.y    = 5; // 例として書いているが基本的にこんな書き方はしない

// コンストラクタ呼び出し
// TestClassインスタンスの作成
var obj = new TestClass();

// Object.prototype -> TestClass.prototype -> obj と継承している
TestClass.prototype.__proto__ === Object.prototype;    // true
obj.__proto__                 === TestClass.prototype; // true
obj.__proto__.__proto__       === Object.prototype;    // true

// TestClass.prototypeはObject.prototypeを継承しているのでyが使える
print(TestClass.prototype.y); // 5
// objはTestClass.prototypeとObject.prototypeを継承しているのでx,yが使える
print(obj.x, obj.y);          // 3 5

■ prototypeと__proto__について

違いについて

prototype 関数オブジェクトが持つプロパティ、何らかのオブジェクトを持つ
__proto__ 上位オブジェクトのprototypeの参照を持つプロパティ

よってさっきの例のこの条件がtrueになる

// prototypeは関数オブジェクトだけ持つことに注意
typeof obj;       // object
typeof TestClass; // function
typeof Object;    // function

TestClass.prototype.__proto__ === Object.prototype;    // true
obj.__proto__                 === TestClass.prototype; // true
obj.__proto__.__proto__       === Object.prototype;    // true

ほとんど上の例を言い換えただけだが__proto__へのアドレスの代入のイメージ

function TestSuper() {}
TestSuper.prototype.a = 5;
TestSuper.prototype.__proto__ = Object.prototype;

// 3行目を実行してもしなくてもtrueになる
TestSuper.prototype.__proto__ === Object.prototype; // true

var obj = function() {};
obj.prototype = new TestSuper();
obj.prototype.__proto__ = TestSuper.prototype;

// 10行目を実行してもしなくてもtrueになる
obj.prototype.__proto__ === TestSuper.prototype; // true

// 以下違いについて
typeof obj.__proto__;
function
typeof obj.prototype;
object
// prototypeはオブジェクトで__proto__はprototypeがある場所を参照している

print(obj.prototype.a); // 5

■ 参考


Be First to Comment

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です