blog

プロトタイプと__proto__がどのような関係にあるのか、JSの理解を深める。

コードの一部を見て、出力について考えてみましょう。 prototypeはプロトタイプです。jsのすべてのオブジェクトはプロトタイプを持っています。しかし、すべてのオブジェクトがprototype属性を...

Dec 2, 2020 · 3 min. read
シェア

コードの一部を見て、出力について考えてください。

let obj = {} console.log(obj.__proto__) // ??
まず、プロトとプロトタイプの意味を理解してください。

プロトタイプとは、プロトタイプ・オブジェクトのことです。jsのすべてのオブジェクトはプロトタイプを持っています。しかし、すべてのオブジェクトがprototype属性を持っているわけではありません。一般的には、関数だけがprototype属性を持っていると言われていますが、実はこれは正確ではありません。JSの組み込みオブジェクトであるObjectやFunctionなどもprototype属性を持っています。prototypeの値はオブジェクトオブジェクトであり、デフォルトではConstruct属性と__proto__属性を含んでいます。prototypeオブジェクトの__proto__属性は、自身のプロトタイプを指します。

proto__はコンストラクタを実行するプロトタイプを指し、プロトタイプ・チェインへのアクセスを向上させるためにブラウザ・ベンダーによって実装されたアクセサ・プロパティです。ES6では標準プロパティとして含まれています。コンストラクタのプロトタイプオブジェクトを指します。場合によっては、Object.getPrototypeOfやObject.setPrototypeOfを使用して、プロトタイプオブジェクトを設定したり読み取ったりすることもできます。

Object.getPrototypeOf(obj) === obj.__proto__; //true

プロトタイプ・チェインと継承

オブジェクトの __proto___ 属性はコンストラクタのプロトタイプ・オブジェクトを指し、そのオブジェクトは自身のプロトタイプを含んでいます。このようなポインティングのレイヤーは、プロトタイプの連鎖を形成します。例えば

Object.prototype === Function.prototype.__proto__ // true

JavaScript オブジェクトはプロパティの動的な「パッケージ」です。JavaScript オブジェクトはプロトタイプオブジェクトへの連鎖を持っています。オブジェクトのプロパティにアクセスしようとするとき、オブジェクトを検索するだけでなく、オブジェクトのプロトタイプ、オブジェクトのプロトタイプのプロトタイプを検索し、一致する名前のプロパティを見つけるか、プロトタイプチェーンの終端に達するまで、チェーン上を検索します。

jsの継承は、プロトタイプによって可能です。プロパティを常に継承させたい場合は、コンストラクタのプロトタイプで定義します。

では、継承はその段階で行われるのですか?冒頭のコードを例にとってみましょう。 最初の行では、リテラルを使ってオブジェクトをインスタンス化していますが、これはnewキーワード+オブジェクトコンストラクタを使ってインスタンス化するのと本質的には変わりません。

  1. オブジェクトを生成します。
  2. このオブジェクトを thisとしてコンストラクタに渡します。
  3. このオブジェクトのプロトタイプをコンストラクタのプロトタイプにポイントし、代入操作にこのオブジェクトを使用します。コンストラクタがオブジェクトを返す場合は、返されたオブジェクトを使用して前述の手順を実行します。 つまり、冒頭の質問に戻ると、プリントアウトはオブジェクトのプロトタイプ・プロパティでなければなりません。

proto__は、コンストラクタのプロトタイプ・オブジェクトへの単なる参照です!

1つ注意すべき点は、__proto__はコンストラクタのプロトタイプ・オブジェクトへの参照でしかないということです。つまり、コンストラクタのプロトタイプを変更すると、プロトタイプ・チェインより下位のオブジェクトも影響を受けます。次の例を見てください。

let Func = function () {}
let a = new Func
a.toString()//"[object Object]"
Func.prototype.toString = () => "2"
a.toString()// "2"

a.toString()メソッドを両側から呼び出すと異なる結果が得られますが、これは途中でプロパティがプロトタイプオブジェクトに追加されるためです。1回目:a自身はtoString属性を持っておらず、コンストラクタのFuncのプロトタイプにもありません。2度目は、対応する属性が Func のプロトタイプに直接あります。実際、オブジェクトとしての Func は、初期化のためのコンストラクタ Function や、オブジェクト自体のプロパティに実装された toString メソッドにはアクセスできますが、プロトタイプチェーンにはアクセスできません。この部分は、インスタンス化メソッドと thisのポインティングに関連しています。これについては、別の記事で詳しく説明します。

プロトタイプ・チェインの終端はNULLです。

プロトタイプ・チェインの終端はNULLです。

a.__proto__.__proto__ === null; //true
Object.protoType.__proto__ === null; //true

関係図添付

Read next

FFmpegのhevc codec_tagの互換性の問題

問題の説明\n\n// ストリーム\nストリーム #0:0[0x101]: video: hevc , yuv420p, , 250 tbr.

Dec 2, 2020 · 6 min read