【学習ログ】MDN JavaScript チュートリアル (20 回目)
はじめに
この記事は、JavaScript チュートリアルの学習ログです。
学習したもの
MDN にある JavaScript のチュートリアルを学習しました。
MDN JavaScript コーナー
┃
┗ チュートリアル
┣ 完全な初心者向け
┃
┣ 中級者向け
┃
┗ 上級者向け
┣ 継承とプロトタイプチェーン(本日の学習箇所)
┣ Strict モード
┣ JavaScript 型付き配列
┣ メモリ管理
┗ 同時実行モデルとイベントループ
概要
チュートリアルで習った事の概要は下記の通りです。
継承とプロトタイプチェーン
プロトタイプベースの継承について学習する。
ノート・メモ
JavaScript には 1 つだけ、継承が発生する要素があります。オブジェクトです。どのオブジェクトもプロトタイプと呼ばれる、他のオブジェクトへの内部的な繋がりを持っています。そのプロトタイプオブジェクトも自身のプロトタイプを持っており、あるオブジェクトのプロトタイプが null に到達するまでそれが続きます。 null は、定義によれば、プロトタイプを持たず、プロトタイプチェーンの最終リンクとなります。
プロパティの継承
JavaScript のオブジェクトはプロパティ(自身のプロパティを指す)の動的な「かばん」であり、プロトタイプオブジェクトへの繋がりを持っています。あるオブジェクトのプロパティにアクセスを試みるとき、そのオブジェクトのみならず、そのオブジェクトのプロトタイプ、プロトタイプのプロトタイプ…と、一致する名前のプロパティが見つかるか、プロトタイプチェーンの終端に到達するまで、そのプロパティが捜索されます。
あるオブジェクトにプロパティをセットすると、自身のプロパティが作られます。この取得と設定の動作の規則の唯一の例外は、 getter または setter とのプロパティの継承が起こるときです。
「メソッド」の継承
JavaScript には、クラスベースの言語が定義する形式の「メソッド」はありません。 JavaScript ではどの関数も、オブジェクトのプロパティという形で追加することができます。継承された関数は、 property shadowing を含めた他のどのプロパティとも同じようにはたらきます。
継承された関数が実行されるときの this の値は、その関数を自身のプロパティとして持つプロトタイプオブジェクトではなく、継承したオブジェクトを指します。
構文構造によるオブジェクト生成
オブジェクトの場合
オブジェクトを新規に作成したとき、オブジェクトはそのPrototype として Object.prototype を持ちます。
オブジェクトは自身に 'hasOwnProperty' という名のプロパティを持っていません。hasOwnProperty は Object.prototype 自身のプロパティです。
Object.prototype のプロトタイプは null です。
プロトタイプチェーンは、オブジェクト ---> Object.prototype ---> null
配列の場合
配列は Array.prototype(indexOf、forEach などのようなメソッドを持っている)から継承します。
プロトタイプチェーンは、配列 ---> Array.prototype ---> Object.prototype ---> null
関数の場合
関数は Function.prototype(call、bind などのようなメソッドを持つ)から継承します。
プロトタイプチェーンは、関数 ---> Function.prototype ---> Object.prototype ---> null
コンストラクタ関数を用いる方法
JavaScript における「コンストラクタ」は、new 演算子を使って呼び出される関数です。
他の関数と区別しやすくする目的で、コンストラクタ関数の関数名の最初の一文字を大文字にしておく慣例があります。
Object.create メソッドを用いる方法
- ECMAScript 5 は Object.create という新しいメソッドを導入しました。このメソッドを呼び出すと、新しいオブジェクトが生成されます。関数の最初の引数が、このオブジェクトのプロトタイプになります。
class キーワードを用いる方法
- ECMAScript 6 はクラスを実装する新たなキーワードのセットを導入しました。これらの要素はクラスベースの言語の開発者にはよく知られたもののようですが、同じではありません。 JavaScript は引き続き、プロトタイプベースの言語です。新たなキーワードは class、constructor、static、extends、super です。
プロトタイプチェーンの上層にあるプロパティの検索時間は、性能に悪影響を及ぼす可能性があり、性能が重要であるコードにおいて、意義深いものになるかもしれません。
加えて、存在しないプロパティへのアクセスは、常にプロトタイプチェーン全体を通過します。
オブジェクトのプロパティを順に処理する際、プロトタイプチェーンにあるすべての列挙可能なプロパティが列挙されます。
hasOwnProperty
あるプロパティがプロトタイプチェーンのどこかではなく、オブジェクト自身に定義されたものであるかどうかを調べるには、すべてのオブジェクトが Object.prototype から継承している hasOwnProperty メソッドを使う必要があります。
hasOwnProperty は JavaScript において唯一、プロトタイプチェーンを通らずにプロパティを扱うものです。
悪い例: ネイティブのプロトタイプの拡張
しばしば見られる設計ミスの 1 つが、Object.prototype あるいは他のビルトインプロトタイプの拡張です。
ビルトインプロトタイプを拡張する唯一の正当な理由は、例えば Array.forEach など、新しい JavaScript エンジンの機能を移植する場合のみです。
JavaScript はすべてが動的で、すべてが実行時であり、一切クラスを持たないことから、 Java や C++から来た開発者にとっていささか紛らわしいものです。すべてはインスタンス(オブジェクト)です。私たちが「クラス」を装っているのは、関数オブジェクトです。
prototype という特別なプロパティは JavaScript の new 演算子と連携しています。プロトタイプオブジェクトへの参照は、新たなインスタンスの内部 Prototype プロパティへとコピーされます。
オブジェクトがメモリ内に生成された後、かつ this が定義されて関数が実行される前 、JavaScript は オブジェクト.Prototype = 関数.prototype をセットします。そうしてインスタンスのプロパティにアクセスするとき、 JavaScript は最初にそのオブジェクトに直接、それらが存在するかどうかを調べ、もし存在しなければ、 Prototype を見ます。
これは prototype に定義したすべての要素がすべてのインスタンスで効果的に共有されている ことを意味しており、もし望むのであれば、後で prototype の一部を変更して、すべての存在するインスタンスにその変更を及ぼすことができます。
prototype は型のためのもので、Object.getPrototypeOf() はインスタンスのためのものと同じです。
使用する複雑なコードを書く前に、プロトタイプの継承モデルを理解することは必要不可欠 です。また、起こり得る性能の問題を回避するために、コードの中のプロトタイプチェーンの長さに気づき、それを解消してください。さらに、ネイティブプロトタイプは、新たな JavaScript の機能の互換性のためでない限り、決して拡張されるべきではありません。
分かった事
プロパティの継承, 「メソッド」の継承, 構文構造によるオブジェクト生成, コンストラクタ関数を用いる方法, Object.create メソッドを用いる方法 あたりまではなんとなく分かりました。
ネイティブのプロトタイプを拡張してはいけない。(モンキーパッチというらしいです。)
分からなかった事
- class キーワードを用いる方法 以降の内容が良く分からなかったです。
まとめ
上級者編だけあって、かなり難しいと感じます。あと少しなので、今はこのまま進めて 理解できなかった部分については、将来的に学習して知識の補完を行いたいと思います。
最後までご覧頂きありがとうございました。