- C#、Javaとかで書いてたクラスからインスタンス生成という概念がJavaScriptにない
- 上記はクラスベースオブジェクト指向でJSとはそもそも立ち位置が違う
- JavaScriptはプロトタイプベースオブジェクトらしい
- なのでクラスベースの言語とはコンストラクタとか継承の仕方は異なる
- ES6でJavaScriptも
class
構文が用意されたけど、
これはクラスベースチックに書くための糖衣構文。内部はプロトタイプベースで動いている
- 便宜上JSでもクラスと言っているが後述するようにクラスも一オブジェクトにすぎない
2つのオブジェクト指向の記法について
プロトタイプベースだと、すべてをオブジェクトと考えインスタンス生成も
オブジェクトから別のオブジェクトを生成しているだけと捉えている幸い、JSは
class
構文でクラスベースチックに書くこともできるので、
両者を書いて差分を見てみる- ソースはMDN Web Docsより一部改変している
- JavaScript のクラス(MDN Web Docs)
/* prototypeプロパティを用いたプロトタイプベースな記法 */ function Person(name){ this.name = name; } Person.prototype.greeting = (name) => { console.log(`I'm ${name}`); } //子クラスの宣言 function Human(name,tribe){ this.name = name; this.tribe = tribe; } //Human(子)クラスのprototypeオブジェクトに親クラスの参照をセットすることで継承を実装 Human.prototype = new Person(); //Human(子)クラスでの追加メソッドは親クラスのインスタンス宣言時より後で行わないと、 //prototypeプロパティがクラス間で共有されるため親のprototypeで上書きされ、無効化される Human.prototype.greeting2 = (name,tribe) => { console.log(`I'm ${name} and ${tribe}`); } //インスタンス(オブジェクト)生成 const man = new Human("Buccellati","Human"); man.greeting(man.name); //I'm Buccellati man.greeting(man.tribe); //I'm Human man.greeting2(man.name,man.tribe); //I'm Buccellati and Human
- JSではすべてのオブジェクトに
prototype
プロパティが自動付与されることで
プロトタイプベースを実現している - クラスの継承も親子オブジェクト間で
prototype
を共有することで可能 - また、コンストラクタは関数オブジェクト全体を指す
/* class構文用いたクラスタイプチックな記載 */ class Person{ constructor(name){ this.name = name; } greeting = () => { console.log(`I'm ${this.name}`); } } //子クラスの宣言 class Human extends Person{ constructor(name,tribe){ //superメソッドで親クラスのコンストラクタを実行(nameプロパティの初期化を行う) super(name); this.tribe = tribe; } greeting2 = () => { console.log(`I'm ${this.name} and ${this.tribe}`); } } const man = new Human("Joruno","Human"); console.log(man.name); //I'm Joruno console.log(man.tribe); //I'm Human man.greeting2(); //I'm Joruno and Human
- 内部含めて動作はprototypeプロパティ使用したソースと同様
prototypeプロパティとプロトタイプチェーン
- JSのNew演算子が実行されると右辺のオブジェクトを参照し、
コンストラクタ実行後、左辺へ生成したオブジェクトを格納する - コンストラクタが関数オブジェクトのため、prototypeプロパティも持つ
- 参照先に存在しないメンバはこのプロパティ経由でさらにメンバを検索する
- 上記ソース例だとgreetingメソッドは
Humanクラス→Human.prototype
の検索で 親クラス参照(Personクラス)を見つけさらにPersonクラス→Person.prototype
で
対象メソッドを見つける- このprototypeプロパティによる複数オブジェクト間の
探索をプロトタイプチェーン
と呼ぶ
- このprototypeプロパティによる複数オブジェクト間の
まとめ
- JavaScriptはJavaみたいなクラス→インスタンスの関係はないよ
- JavaScriptはプロトタイプベースOOPのため上記の関係は
オブジェクト→別オブジェクトに過ぎないよ - どのオブジェクトもprototypeプロパティをもっていてこいつを経由で
大抵のメンバを探索できるよ(プロトタイプチェーン) - TODO:#2でプロトタイプとクラスそれぞれのOOPの
有用性を書けるようになったら書く