prototypeと__proto__ [JavaScript]
もりけん塾(@terrace_tech)にて、JavaScriptを勉強しています。
現在、これまで何となく書いてきたJavaScriptの基礎を見直すべく、まずは今自分の中で理解の浅い項目について調べています。
今回は、prototypeや__proto__について、分かってきたことをまとめていきます。
※本エントリーで扱うprototypeは、JavaScriptオブジェクトのインスタンスのプロパティのprototypeではなく、コンストラクタ関数のプロパティのprototypeです。
prototypeや_proto_を理解する必要がある理由
JavaScriptは、オブジェクトとプロトタイプチェーンによって成り立っています。この仕組みをちゃんと理解していないと、JavaScriptについての色々な説明を読んでも理解出来ないのだと痛感する出来事がありました。
JavaScriptの苦手な部分を1つずつ潰していくという学習の方向性が決まった時、私は最初にclassについて調べ始めました。深い理由はなく、たまたまリストアップしたJavaScript苦手項目の一番上に「classがどういうものか分からない」と書いてあったからです。
classのことを調べていくうちに、コンストラクタ関数やファクトリ関数と呼ばれるものも、class同様の機能を持っていることを知りました。なのでそれら2つについても並行して調べていくことにしました。
「class」について調べれば「コンストラクタ関数」や「ファクトリ関数」について調べる必要が発生し、「コンストラクタ関数」を調べれば「this」や「new」キーワードについて知る必要が発生し、調べる項目は増え続けました。しかし途中で、どうしても解説の意味が理解出来なくなり、前に進めなくなってしまいました。
上に挙げた項目はどれを取っても、prototypeの仕組みが分かっていないと、理解することが出来ないようになっていたのです。
この点に気付いた時、私はprototypeはJavaScriptを勉強する上で避けて通れない根幹の部分の知識なのだと痛感しました。そして、prototypeの仕組みを理解することから始めようと決意しました。
今後のJavaScriptの学習をスムーズに進めていくためにも、まずはベースとなるprototypeのことを最初の段階で理解しておくことが重要であると私は思います。
prototypeの他に _proto_ というものが存在する
prototypeについて調べようとした時に一緒に出てきたのが_proto_という言葉です。最初、私はprototypeと_proto_の違いがどうしても理解出来ませんでした。
漠然と、prototypeは継承を可能にするものだ、というようなことは分かっていたのですが、詳しい仕組みは理解していませんでした。何より_proto_が何者なのか、それは概念なのかオブジェクトなのかすら理解出来ずにいました。
prototypeと_proto_の違い
prototypeと_proto_の違いについては、色々と調べた結果、下記の通りに理解しました。
prototype
prototypeは、コンストラクタ関数を実行することによって生まれるプロパティ(※本ページ最初の注釈を参照)です。
コンストラクタ関数によって、インスタンスへの継承を実現させるために生み出されます。
_proto_
_proto_は、すべてのオブジェクトが持っているプロパティです。
コンストラクタ関数によって作られたインスタンス自体は、prototypeを持っていません。
しかし_proto_を持っていることによって、コンストラクタ関数のprototype(=自身が継承していて使うことが出来るprototype)への参照を持つことが出来ます。
prototypeと_proto_が作られていく過程
言葉で理解しようすると非常に難しかったのですが、もりた先生に「実際にコンソールで出力したものを1つ1つ画像化していくと、自分も納得するし説明にも説得力が生まれますよ」とアドバイスを頂きました。
なので実際にコンソールに出力した値を見ながら、prototypeと_proto_が作られていく過程を順を追ってチェックしていきます。
1.
まず、コンストラクタ関数Dogを作ります。
2.
コンストラクタ関数Dogの詳細をコンソールで見てみると、prototypeというプロパティがあるのが分かります。
3.
prototypeには、手動でメソッドを追加することができます。
次のように記述し、コンストラクタ関数Dogのprototypeにbarkメソッドを追加してみます。
4.
再びコンストラクタ関数Dogをコンソールで見てみると、prototypeにbarkメソッドが追加されているのが分かります。prototypeは、プロパティやメソッドを入れておくバケツのような役割を果たしています。
5.
コンストラクタ関数Dogを元に、インスタンス pochi
を作ります。
6.
上記で作られたインスタンス pochi
の中身を見てみると、_proto_というプロパティが作られています。
_proto_は、すべてのオブジェクトが持っているプロパティです。
_proto_は、prototypeへのプロパティアクセサーの役割を果たします。
(プロパティアクセサーの例:dog.nameの .name の部分など)
なのでpochiが継承しているprototype一覧は、pochi._proto_と書くと表示することが出来ます。
下の図はpochi._proto_と書いて出力された、pochiが継承しているprototype一覧です。先ほど作ったbarkメソッドも入っています。
7.
上記の通り、インスタンスpochi
はbark()メソッドを継承しているので、pochi.bark()
と書くと、メソッドを実行することができます。
(pochiは英語圏の犬なので "Woof" と鳴きます)
まとめ
prototypeや_proto_について理解すると、今後classやコンストラクタ関数、newなどオブジェクト関連のコンセプトを学ぶ際の下地が出来てきます。これからのJavaScriptの学習のためにも、是非抑えておくべきポイントだと思います。
参考にしたサイト
prototypeや_proto_について調べる際に参考にした、分かりやすい解説の載ったサイトです。
Object のプロトタイプ|MDN Web Docs
プロトタイプオブジェクトやprototypeプロパティのことについて詳しく載っています。
JavaScript Prototype|JavaScript Tutorial
prototypeがどのようにオブジェクトと繋がっているか等を、分かりやすい図で解説しています。
なるほど。。_proto_とprototypeの違い|武骨日記
もりた先生の記事です。コード付きで解説が載っています。
proto VS. prototype in JavaScript|Stack Overflow
_proto_ と prototypeの違いを、色々な人が分かりやすく解説しています。
JavaScriptを教えていただいている、もりた先生の詳細はこちらです。
[もりけん塾]
ブログ:http://kenjimorita.jp
Twitter:https://twitter.com/terrace_tech