3
1

More than 3 years have passed since last update.

prototypeと__proto__

Last updated at Posted at 2020-08-23

Javaに慣れたからちょっと理解しづらかった

プロトタイプ

JavaScriptでは、全てのものがオブジェクト(またはそのインスタンス)である

そして、全てのオブジェクトはprototypeオブジェクトおよび__proto__プロパティを持っている

  • __proto__: これはポインタみたいなプロパティである。どこかのprototypeを指している

  • prototype: 子オブジェクトに継承させたいものをこの中に記述する。(インスタンスはこれを持たない)

    prototypeもオブジェクトなので、その中にも__proto__プロパティがある

プロトタイプチェーン

あるインスタンスから、メソッドを呼び出す時の話。

もしインスタンス自身にメソッドが見つからない場合、

そのインスタンスの__proto__プロパティから、どこかのprototypeに辿り、その中で探す。

それでもない場合、さらにそのprototype内の__proto__より、新たなprototypeに辿り着く。

こうやって繰り返して、最終的に__proto__ === nullとなり、undefinedが返される。

具体的な関係

Object.prototype.__proto__ === null

Object.__proto__ === Function.prototype

// 生成したインスタンスの__proto__
(new Object()).__proto__ === Object.prototype



Function.prototype.__proto__ === Object.prototype

Function.__proto__ === Function.prototype

// 生成したインスタンスの__proto__
(new Function()).__proto__ === Function.prototype



Array.prototype.__proto__ === Object.prototype

Array.__proto__ === Function.prototype

// 生成したインスタンスの__proto__
(new Array()).__proto__ === Array.prototype

自作コンストラクタで生成したインスタンス

例えば下のようなコンストラクタでインスタンスを生成したとする

function Person(name){
    this.name = name;
}
const person = new Person("yuki");

関係性は以下のようになる

person.__proto__ === Person.prototype
Person.prototype.constructor.__proto__ === Function.prototype
Person.prototype.constructor.prototype === Person.prototype

Object.create()で生成したインスタンス

Object.create()を使ってもインスタンスを生成できる

const anotherPerson = Object.create(person);

このとき、anotherPerson.__proto__が参照しているのは、personインスタンスとなる

つまり、personに何かを追加すれば、anotherPersonもそれを使える(anotherPerson.__proto__で探す)

Person.prototypeに追加して、anotherPersonでも使える(anotherPerson.__proto__.__proto__で探す)

=で生成したインスタンス

const person01 = person

Object.create()と違って、person01.__proto__ === person.__proto__ === Person.prototype

コンストラクタ

コンストラクタ関数の値は、prototype内のconstructorプロパティに保存されている

インスタンスからは、インスタンス.constructorでアクセスできる(実際はインスタンス.__proto__.constructor)

こういうことを利用して、インスタンスからコンストラクタを入手し、それで新しいインスタンスを生成できる

const person02 = new anotherPerson.constructor("abc");
person02.__proto__ === Person.prototype    // true

anotherPerson.__proto__が参照しているのは、personインスタンス

しかし、constructorというプロパティはanotherPersonにもpersonにもなく、

結局Person.prototypeまで探しに行ったので、person02.__proto__ === Person.prototypeがtrueとなる

constructor.name

インスタンス.constructor.nameで、コンストラクタ関数の関数名を取得できる

プロトタイプの変更

コンストラクタ関数のprototypeプロパティを変更すれば、

コンストラクタから作成されたすべてのオブジェクトインスタンスで使用可能になる

ただし、prototypeに追加した関数内部で、メンバのプロパティを利用したいなら、

thisキーワードを使う必要がある

参考記事

Object のプロトタイプ
図で理解するJavaScriptのプロトタイプチェーン
JavaScriptのプロトタイプチェーンを深堀りする
JavaScript のプロトタイプを理解する
JavaScriptのプロトタイプからオブジェクト指向を学ぶ

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1