概要
JavaScript勉強シリーズ
- JavaScriptのthisについてメモ
- JavaScriptのコンストラクタについて
- JavaScriptのwindowについてのメモ
- JavaScriptのプロトタイプ継承について
- JavaScriptのプロトタイプチェーンについてメモ
- JavaScriptのスコープについてメモ
- JavaScriptの論理演算による存在チェックについて
- JavaScriptのクロージャについてメモ
- JavaScriptのグローバル変数の衝突について
JavaScriptのプロトタイプチェーンについてメモ
↑以前プロトタイプ継承についてまとめたがその続きとしてプロトタイプチェーンという機能について調べる
プロトタイプチェーンについて
プロトタイプ継承の記事から以下の前提をおさらいしておく
- 全ての関数オブジェクトはprototypeという名前のプロパティを持つ
- 関数オブジェクトのコンストラクタによって生成されたオブジェクトは全てprototypeオブジェクトへの(隠し)リンクを持つ
プロトタイプチェーンとはオブジェクトが他のオブジェクトのプロトタイプとなる連鎖のことを呼ぶ
prototypeオブジェクトを「親」と表現するとプロトタイプチェーンの動作として以下のようにプロパティを探す
- オブジェクト自身のプロパティ
- 1.のオブジェクトの「親」のオブジェクトのプロパティ(1で見つからなかったら)
- 2.のオブジェクトの「親」のオブジェクトのプロパティ(2で見つからなかったら)
- 探索が終わるまで繰り返す (「親」の終端に当たるのは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
参考
- パーフェクトJavaScript (書籍)
- 継承とプロトタイプチェーン
- JavaScript:プロトタイプチェーン詳解!prototype と __proto__ について
- プロトタイプチェーンをもっと理解する
コメントを書く
コメント一覧