ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScript ES2015のオブジェクト継承のパターン
an
インターフェイスは、(タイプ化された)古典的なOOP言語の一般的な機能です。これにより、クラスに含まれる方法(および時にはプロパティ)を定義できます。そのクラスがそうでない場合、コンパイラはエラーを引き起こします。猫が攻撃()またはwalk()メソッドを持っていなかった場合、次のタイプスクリプトコードはエラーを引き起こします:
<span>class Animal(object): </span> <span>def walk(self): </span> <span># ... </span> <span>class Hostile(object): </span> <span>def attack(self, target): </span> <span># ... </span> <span>class Dog(Animal): </span> <span># ... </span> <span>class Cat(Animal, Hostile): </span> <span># ... </span> dave <span>= Cat(); </span>dave<span>.walk(); </span>dave<span>.attack(target); </span>
多重継承は、ダイヤモンドの問題に苦しんでいます(2つの親クラスが同じ方法を定義する場合)。一部の言語では、ミキシンのような他の戦略を実装することにより、この問題をかわします。 ミックスインは、方法のみを含む小さなクラスです。これらのクラスを拡張する代わりに、ミックスインは別のクラスに含まれています。たとえば、PHPでは、特性を使用してミキシンが実装されています
a Recap:ES2015 Class Syntax<span>interface Hostile { </span> <span>attack(); </span><span>} </span> <span>class Animal { </span> <span>walk(); </span><span>} </span> <span>class Dog extends Animal { </span> <span>// ... </span><span>} </span> <span>class Cat extends Animal implements Hostile { </span> <span>attack() { </span> <span>// ... </span> <span>} </span><span>} </span>
class foo {...} foo
という名前のクラスについて説明しますclass foo extends bar {...} foo、他のクラスを拡張するクラスについて説明します
という名前のメソッドを作成します
前に提案されたように、このアプローチは継承に依存しています。複数のクラスを継承するには、複数の継承またはミキシンが必要になります。
<span>class Animal { </span> <span>// ... </span><span>} </span> <span>trait Hostile { </span> <span>// ... </span><span>} </span> <span>class Dog extends Animal { </span> <span>// ... </span><span>} </span> <span>class Cat extends Animal { </span> <span>use Hostile; </span> <span>// ... </span><span>} </span> <span>class Robot { </span> <span>use Hostile; </span> <span>// ... </span><span>} </span>
別のアプローチは、定義された後にクラスを検証するユーティリティ関数を作成することです。この例は、ちょっと待って、JavaScriptは複数の継承をサポートしています!アンドレア・ジャンマルチによる。セクション「基本的なオブジェクト。実装関数チェック」を参照してください。
object.Assign(childclass.prototype、mixin ...)
<span>class Foo {} </span><span>console.log(typeof Foo); // "function" </span>Pre-ES2015、継承にプロトタイプを使用しました。すべての関数にはプロトタイププロパティがあります。 new MyFunction()を使用してインスタンスを作成すると、プロトタイプがインスタンスのプロパティにコピーされます。インスタンスにないプロパティにアクセスしようとすると、JavaScriptエンジンはプロトタイプオブジェクトで調べようとします。
実証するには、次のコードをご覧ください
これらのプロトタイプオブジェクトは、実行時に作成および変更できます。当初、私は動物と敵対的にクラスを使用しようとしました:
<span>class Animal(object): </span> <span>def walk(self): </span> <span># ... </span> <span>class Hostile(object): </span> <span>def attack(self, target): </span> <span># ... </span> <span>class Dog(Animal): </span> <span># ... </span> <span>class Cat(Animal, Hostile): </span> <span># ... </span> dave <span>= Cat(); </span>dave<span>.walk(); </span>dave<span>.attack(target); </span>クラスの方法は列挙できないため、上記は機能しません
。実際には、これはObject.Assign(...)をクラスからコピーしないことを意味します。これにより、メソッドをあるクラスから別のクラスにコピーする関数を作成することも困難になります。ただし、各メソッドを手動でコピーできます 別の方法は、クラスを捨てて、オブジェクトをミックスインとして使用することです。肯定的な副作用は、ミックスオブジェクトを使用してインスタンスを作成し、誤用を防ぐことができないことです。
<span>interface Hostile { </span> <span>attack(); </span><span>} </span> <span>class Animal { </span> <span>walk(); </span><span>} </span> <span>class Dog extends Animal { </span> <span>// ... </span><span>} </span> <span>class Cat extends Animal implements Hostile { </span> <span>attack() { </span> <span>// ... </span> <span>} </span><span>} </span>pro
<span>class Animal { </span> <span>// ... </span><span>} </span> <span>trait Hostile { </span> <span>// ... </span><span>} </span> <span>class Dog extends Animal { </span> <span>// ... </span><span>} </span> <span>class Cat extends Animal { </span> <span>use Hostile; </span> <span>// ... </span><span>} </span> <span>class Robot { </span> <span>use Hostile; </span> <span>// ... </span><span>} </span>ミックスインは初期化できません
object.Assign()は少しあいまいです
このアプローチは実用的ではありません。インスタンスの代わりに新しいオブジェクトを返すため、基本的に次のように相当します。
<span>class Foo {} </span><span>console.log(typeof Foo); // "function" </span>後者がより読みやすいことに同意できると思います。
pro
<span>class IAnimal { </span> <span>walk() { </span> <span>throw new Error('Not implemented'); </span> <span>} </span><span>} </span> <span>class Dog extends IAnimal { </span> <span>// ... </span><span>} </span> <span>const robbie = new Dog(); </span>robbie<span>.walk(); // Throws an error </span>
動作します、私は推測しますか?
<span>function <span>MyFunction</span> () { </span> <span>this.myOwnProperty = 1; </span><span>} </span><span>MyFunction.prototype.myProtoProperty = 2; </span> <span>const myInstance = new MyFunction(); </span> <span>// logs "1" </span><span>console.log(myInstance.myOwnProperty); </span><span>// logs "2" </span><span>console.log(myInstance.myProtoProperty); </span> <span>// logs "true", because "myOwnProperty" is a property of "myInstance" </span><span>console.log(myInstance.hasOwnProperty('myOwnProperty')); </span><span>// logs "false", because "myProtoProperty" isn’t a property of "myInstance", but "myInstance.__proto__" </span><span>console.log(myInstance.hasOwnProperty('myProtoProperty')); </span>
cons
<span>class Animal { </span> <span>walk() { </span> <span>// ... </span> <span>} </span><span>} </span> <span>class Dog { </span> <span>// ... </span><span>} </span> <span>Object.assign(Dog.prototype, Animal.prototype); </span>
非常にあいまいな
ES2015クラスの構文
からゼロの利点このアプローチは、実行時にクラスを定義するJavaScriptの能力を活用しています。
pro
すべての情報がクラス宣言ヘッダーにあるため、
<span>Object.assign(Cat.prototype, { </span> <span>attack: Hostile.prototype.attack, </span> <span>walk: Animal.prototype.walk, </span><span>}); </span>理解しやすい
<span>const Animal = { </span> <span>walk() { </span> <span>// ... </span> <span>}, </span><span>}; </span> <span>const Hostile = { </span> <span>attack(target) { </span> <span>// ... </span> <span>}, </span><span>}; </span> <span>class Cat { </span> <span>// ... </span><span>} </span> <span>Object.assign(Cat.prototype, Animal, Hostile); </span>cons
このトピックを調査し、それに関する記事を書くことにしたとき、JavaScriptのプロトタイプモデルがクラスを生成するのに役立つことを期待していました。クラスの構文はメソッドを許可できないため、オブジェクトの操作ははるかに難しくなり、ほとんど非実用的になります。
クラスの構文は、JavaScriptがクラスベースのOOP言語であるという幻想を作成する可能性がありますが、そうではありません。ほとんどのアプローチを使用すると、複数の継承を模倣するためにオブジェクトのプロトタイプを変更する必要があります。クラスの工場関数を使用する最後のアプローチは、ミキシンを使用してクラスを構成するための許容可能な戦略です。プロトタイプベースのプログラミングが制限されていると思う場合は、考え方を見てみたいと思うかもしれません。プロトタイプは、あなたが利用できる比類のない柔軟性を提供します。
何らかの理由で、クラシックプログラミングを依然として好む場合、JavaScriptにコンパイルする言語を調べたい場合があります。たとえば、TypeScriptは、(オプションの)静的タイピングと他の古典的なOOP言語から認識されるパターンを追加するJavaScriptのスーパーセットです。プロジェクトで上記のアプローチのいずれかを使用しますか?より良いアプローチを見つけましたか?コメントでお知らせください!
この記事は、ジェフ・モット、スコット・モリナリ、ビルダン・ソフト、ジョーン・インによって査読されました。 SetePointコンテンツを最高にするためにSitePointのピアレビュアーのすべてに感謝します!JavaScript ES2015オブジェクト継承に関するよくある質問
JavaScriptの古典的継承とプロトタイプの継承の違いは何ですか?JavaやCなどの言語でよく使用される古典的継承は、クラスに基づいています。クラスはオブジェクトの青写真を定義し、オブジェクトはクラスのインスタンスです。継承は、スーパークラスからサブクラスを作成することで達成されます。一方、JavaScriptは、オブジェクトが他のオブジェクトから直接継承するプロトタイプ継承を使用します。これは、オブジェクトを実行時に動的に拡張または変更できるため、より柔軟です。オブジェクトの親に関数を呼び出します。コンストラクターで使用する場合、「スーパー」キーワードが単独で表示され、「この」キーワードが使用される前に使用する必要があります。 「スーパー」キーワードを使用して、メソッド内の親オブジェクトの関数を呼び出すこともできます。
JavaScriptでは、すべての関数とオブジェクトには「プロトタイプ」プロパティがあります。このプロパティは、別のオブジェクトであるプロトタイプオブジェクトへの参照です。関数が作成されると、そのプロトタイプオブジェクトは、関数のプロトタイププロパティを介して作成およびリンクされます。コンストラクター関数を使用してオブジェクトを作成すると、コンストラクターのプロトタイプからプロパティとメソッドを継承します。ただし、ミキシンを使用して間接的に達成できます。ミックスインは、あるオブジェクトから別のオブジェクトにプロパティをコピーすることを含む手法です。これにより、オブジェクトは複数のソースからプロパティとメソッドを継承できます。クラス内のオブジェクトを作成および初期化するために使用される特別な方法。継承のコンテキストでは、サブクラスコンストラクターは、「この」キーワードを使用する前に「スーパー」キーワードを使用してスーパークラスコンストラクターを呼び出す必要があります。 >
以上がJavaScript ES2015のオブジェクト継承のパターンの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。