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

Published: 2016年3月17日 by tomsato

概要

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

参考

コメントを書く

※ 個別に返信が必要な時のみご記入ください

※ Emailは公開されません

※ 承認されると名前・コメントが下記に表示されます

コメント一覧

最近の投稿

ビジュアルリグレッションテストについてまとめ、ネットで調べると数多くのライブラリがありどれがどんな立ち位置なのか全体像がわかりずらかったのでどんな種類があるのか入門の入門としてまとめます、またPlaywrightを使って実際に触ってみました

社内ツールなどの超小規模なAPIをGolangで実装する際にフレームワークを使うべきかを、実際にnet/httpを使った実装とフレームワークを使った実装を比較することでどれだけ優位性があるかを見ていきたいと思います。今回はフレームワークにはシンプルで使いやすそうなEchoを使うことにします。

vue-pdfを使ってNuxt.jsで作成しているアプリケーションに pdfスライドを表示させるサンプルを作成しました README.md通りに実装してもうまくいかないところがあったのでそのあたり含めてまとめます

Vue.js / Nuxt.jsにおけるログインの実装方法をまとめる Auth0やNuxt.jsのAuth Moduleとmiddlewareについて調べつつサンプルを作成することで理解を深める

コンポーネント設計について考える Atomic DesignやPresentational Component, Container Componentについてまとめつつ 自分だったらVue.js / Nuxt.jsでどういうコンポーネント設計にするかについてまとめます

カテゴリ一覧

タグ一覧