ECMAScript は実装の継承のみをサポートしており、その実装の継承は主にプロトタイプ チェーンに依存します。
プロトタイプチェーン
プロトタイプ チェーンの基本的な考え方は、プロトタイプを使用して、ある参照型に別の参照型のプロパティとメソッドを継承させることです。各コンストラクターにはプロトタイプ オブジェクトがあり、プロトタイプ オブジェクトにはコンストラクターへのポインターが含まれ、インスタンスにはプロトタイプ オブジェクトへのポインターが含まれます。プロトタイプ オブジェクト A を型 B の別のインスタンスと等しくすると、プロトタイプ オブジェクト A は B のプロトタイプ オブジェクトを指すポインターを持ち、B の対応するプロトタイプ オブジェクトはそのコンストラクターへのポインターを格納します。 B のプロトタイプ オブジェクトが別の型のインスタンスである場合、上記の関係は依然として保持され、同様にインスタンスとプロトタイプのチェーンが形成されます。
インスタンス、コンストラクター、プロトタイプ間の関係図は次のとおりです。
person.constructor が親を指すようになりました。これは、Child.prototype が親のプロトタイプを指し、Parent プロトタイプ オブジェクトのコンストラクターが親を指すためです。
読み取りモードでインスタンス プロパティにアクセスすると、まずインスタンス内でプロパティが検索され、プロパティが見つからない場合は、インスタンスのプロトタイプの検索が続行されます。プロトタイプ チェーンを介した統合では、チェーンの終わりに到達するまで検索が続行されます。
たとえば、person.getParentValue() メソッドを呼び出す場合、1) インスタンスを検索し、2) Child.prototype を検索し、3) getParentValue() メソッドが見つかったら停止します。
1. デフォルトのプロトタイプ
前の例で示したプロトタイプ チェーンにはリンクがありません。すべての参照型はデフォルトで Object を継承し、この継承もプロトタイプ チェーンを通じて実装されます。したがって、デフォルトのプロトタイプには、Object.prototype を指す内部ポインターが含まれています。これが、すべてのカスタム型が toString() や ValueOf() などのデフォルト メソッドを継承する根本的な理由です。言い換えれば、Object.prototype はプロトタイプ チェーンの終端です。
2. プロトタイプとインスタンスの関係を決定します
プロトタイプとインスタンスの関係は 2 つの方法で決定できます。1 つ目は、instanceOf 演算子を使用する方法で、2 つ目は、isPrototypeOf() メソッドを使用する方法です。
instanceOf プロトタイプ チェーンに表示されるコンストラクターはすべて true
console.log(person instanceOf Child);//true console.log(person instanceOf Parent);//true console.log(person instanceOf Object);//true isPrototype(),只要是原型链中出现过的原型,都可以说是该原型链所派生出来的实例的原型,因此也返回true. console.log(Object.prototype.isPrototypeOf(instance));//true console.log(Parent.prototype.isPrototypeOf(instance));//true console.log(Child.prototype.isPrototypeOf(instance));//true
3. メソッドを慎重に定義します
サブタイプは、スーパータイプのメソッドをオーバーライドしたり、スーパータイプに存在しないメソッドを追加したりする必要がある場合があります。 注: プロトタイプにメソッドを追加するコードは、プロトタイプを置き換えるステートメントの後に配置する必要があります。
getParentValue() が Child インスタンスを通じて呼び出された場合、この再定義されたメソッドが呼び出されますが、getParentValue() が Parent インスタンスを通じて呼び出された場合、元のメソッドが呼び出されます。
これら 2 つのメソッドは、Parent のインスタンスがプロトタイプを置き換えた後に定義する必要があることに注意することが重要です。
特別な注意が必要なもう 1 つの点は、プロトタイプ チェーンを介して継承を実装する場合、オブジェクト リテラルを使用してプロトタイプ メソッドを作成することはできません。これは、プロトタイプ チェーンが上書きされるためです。
上記のコードは、Parent のインスタンスを Child のプロトタイプ オブジェクトに割り当て、そのプロトタイプをリテラルに置き換えるだけです。実際には、Child プロトタイプには Parent のインスタンスではなく Object のインスタンスが含まれます。なので、私たちが想像していたプロトタイプのチェーンは切断されます。 親と子の間にはつながりがありません。
4. プロトタイプチェーンの問題
プロトタイプ チェーンは非常に強力で、継承の実装に使用できますが、主な問題は、参照型の値を含むプロトタイプ プロパティがすべてのインスタンスで共有されることです。そこで、コンストラクターでインスタンスのプロパティを定義します。ただし、プロトタイプを介して継承が実装されると、プロトタイプ オブジェクトは実際には別の型のインスタンスになります。したがって、コンストラクターで最初に定義されたインスタンス プロパティはプロトタイプ プロパティになります。
例は次のとおりです:
friend 属性は Parent コンストラクターで定義されており、その属性値は配列 (参照型の値) です。このようにして、Parent の各インスタンスには独自の friends 属性が含まれます。 Child がプロトタイプ チェーンを通じて Parent を継承すると、Child.prototype も friends 属性を使用します。これは、friends 属性が Child.prototype で定義されているかのようになります。このようにして、Child のすべてのインスタンスは friends 属性を共有するため、kid1.friends に加えた変更は kid2.friends にも反映されます。これは明らかに私たちが望んでいることではありません。
プロトタイプ チェーンのもう 1 つの問題は、サブタイプのインスタンスを作成するときに、すべてのオブジェクト インスタンスに影響を与えずにスーパータイプのコンストラクターにパラメーターを渡すことができないことです。したがって、プロトタイプチェーンを単独で使用することはほとんどありません。
コンストラクターを借用
プロトタイプに参照型の値が含まれることによって引き起こされるいくつかの問題を解決するために、コンストラクターを借用するテクノロジーが導入されました。この手法の基本的な考え方は、サブタイプ コンストラクター内でスーパータイプ コンストラクターを呼び出すことです。
Parent.call(this) は、新しく作成された Child インスタンスのコンテキストで Parent コンストラクターを呼び出します。新しく作成された Child インスタンスのコンテキストで Parent コンストラクターを呼び出します。このようにして、Parent() 関数で定義されたオブジェクト初期化コードが、新しい Child オブジェクト (ここでは kid1 オブジェクトと kid2 オブジェクト) に対して実行されます。このようにして、各 Child インスタンスは friends プロパティの独自のコピーを持つことになります。
コンストラクターを借用することで、サブタイプ コンストラクター内のスーパータイプ コンストラクターにパラメーターを渡すことができます。
サブタイプの親密度が親クラスのコンストラクターによってオーバーライドされないようにするには、親クラスのコンストラクターを呼び出した後にサブタイプのプロパティを追加します。
コンストラクターの問題:
コンストラクター パターンの問題は、メソッドがすべてコンストラクター内で定義されており、関数の再利用が不可能であるため、コンストラクターを借用するパターンが単独で使用されることはほとんどありません。
結合継承
結合継承とは、プロトタイプの連鎖とコンストラクターの借用の技術を組み合わせて、両方の長所を活用することを指します。つまり、プロトタイプ チェーンを使用してプロトタイプのプロパティとメソッドの継承を実現し、コンストラクターを借用してインスタンス プロパティの継承を実現します。
Person建構子定義了兩個屬性:name和friends。 Person的原型定義了一個方法sayName()。 Child建構函式在呼叫Parent建構函式時,傳入了name參數,緊接著又定義了自己的屬性age。然後將Person的實例賦值給Child的原型,然後又在該原型上定義了方法sayAge().這樣,兩個不同的Child實例既分別擁有自己的屬性,包括引用類型的屬性,又可以使用相同的方法了。
組合繼承避免了原型鍊和建構函數的缺陷,融合了他們的有點,成為JavaScript中最常用的繼承模式。而且,instanceOf和isPropertyOf()也能夠辨識基於組合繼承所建立的物件。
最後,關於JS物件和繼承都還有幾種模式沒有寫,或者說,我自己也還未去深刻研究,但是,我想,首先將組合模式應用的游刃有餘。並且,對於為何選用組合模式,知其然,知其所以然。
關於JavaScript實作繼承的幾種方式(推薦),小編就跟大家介紹到這裡,希望對大家有幫助!