ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScript ES2015のオブジェクト継承のパターン

JavaScript ES2015のオブジェクト継承のパターン

Lisa Kudrow
Lisa Kudrowオリジナル
2025-02-16 11:38:39822ブラウズ

JavaScript ES2015のオブジェクト継承のパターン

キーテイクアウト

    ES2015を使用して、JavaScriptには、コードを清潔に保ち、階層の深さを最小限に抑え、重複コードを避けるためにクラスを定義するための特に構文があります。
  • 複数の継承は、いくつかの古典的なOOP言語でサポートされている機能であり、複数のベースクラスから継承するクラスを作成できます。ただし、2つの親クラスが同じ方法を定義するダイヤモンドの問題に苦しんでいます。 メソッドのみを含む小さなクラスは、ダイヤモンドの問題をかわすために使用される別の戦略です。これらのクラスを拡張する代わりに、ミキシンは別のクラスに含まれています。
  • クラスの構文は、JavaScriptがクラスベースのOOP言語であるという幻想に与えていますが、そうではありません。ほとんどのアプローチでは、複数の継承を模倣するためにオブジェクトのプロトタイプを変更する必要があります。クラスの工場関数を使用することは、ミキシンを使用してクラスを作成するための許容可能な戦略です。
  • 待望のES2015(以前はES6として知られていた)の待望の到着により、JavaScriptにはクラスを定義するための特に構文が装備されています。この記事では、クラスの構文を活用して、より小さな部品からクラスを作成できるかどうかを調べます。
  • コードを清潔に保つには、階層の深さを最小限に抑えることが重要です。クラスをどのように分割するかについて賢くなることが役立ちます。大きなコードベースの場合、1つのオプションは、小さな部品からクラスを作成することです。クラスの作成。また、複製コードを避けるための一般的な戦略でもあります
  • プレーヤーが動物の世界に住んでいるゲームを構築していると想像してください。友人は友人であり、他の人は敵対的です(私のような犬の人は、すべての猫が敵対的な生き物だと言うかもしれません)。動物を拡張するクラスの敵対的なクラスを作成するために、猫の基本クラスとして機能することができます。ある時点で、人間に害を及ぼすように設計されたロボットを追加することにしました。最初に行うことは、ロボットクラスを作成することです。現在、同様のプロパティを持つ2つのクラスがあります。たとえば、HostileanimalとRobotの両方が攻撃することができます。
  • 敵対的な別のクラスまたはオブジェクトで敵意を何らかの形で定義できれば、それをロボットとして両方の猫と再利用することができます。さまざまな方法でそれを行うことができます
多重継承JavaScript ES2015のオブジェクト継承のパターンは、いくつかの古典的なOOP言語のサポートの機能です。名前が示すように、それは私たちに複数の基本クラスから継承するクラスを作成する能力を与えてくれます。 CATクラスが次のPythonコードで複数のベースクラスを拡張する方法をご覧ください:

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>

ES2015クラスに飛び込む機会がなかった場合、またはそれらについて十分に知らないと感じた場合は、Jeff Mottのオブジェクト指向のJavaScriptを必ず読んでください。 > 一言で言えば

class foo {...} foo

という名前のクラスについて説明します

class foo extends bar {...} foo、他のクラスを拡張するクラスについて説明します

  • クラスブロック内で、そのクラスのプロパティを定義できます。この記事では、コンストラクターと方法を理解する必要があります。
  • constructor(){...}は、作成時に実行される予約された関数です(new foo())
foo(){...} foo

という名前のメソッドを作成します

    クラスの構文は、JavaScriptのプロトタイプモデルよりも主に構文糖です。クラスを作成する代わりに、関数コンストラクターを作成します:
  • ここでの要点は、JavaScriptがクラスベースのOOP言語ではないことです。構文は欺cept的であると主張するかもしれません。 ES2015クラスの構成
  • エラーをスローするダミーメソッドを作成することにより、
インターフェイスを模倣することができます。継承されたら、エラーを回避するために関数をオーバーライドする必要があります:

前に提案されたように、このアプローチは継承に依存しています。複数のクラスを継承するには、複数の継承またはミキシンが必要になります。
<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は複数の継承をサポートしています!アンドレア・ジャンマルチによる。セクション「基本的なオブジェクト。実装関数チェック」を参照してください。

複数の継承とミキシンを適用するさまざまな方法を探る時間。以下のすべての検査された戦略は、githubで入手できます。

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>
ミックスインは初期化できません

    cons
には、コードの追加行が必要です

object.Assign()は少しあいまいです
    ES2015クラスを操作するためのプロトタイプの継承を再発明する
  • コンストラクターにオブジェクトを構成する
  • ES2015クラスを使用すると、コンストラクター内のオブジェクトを返すことでインスタンスをオーバーライドできます。
  • その機能を活用して、サブクラス内の複数のクラスからオブジェクトを作成できます。 Object.Assign(...)はまだミックスクラスではうまく機能しないことに注意してください。そのため、ここでもオブジェクトを使用しました。

これは、上記のコンテキストでのクラス(非記録的な方法を使用)を指すため、Object.Assign(...、これ)は猫の方法をコピーしません。代わりに、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クラスの構文

からゼロの利点
    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では、すべての関数とオブジェクトには「プロトタイプ」プロパティがあります。このプロパティは、別のオブジェクトであるプロトタイプオブジェクトへの参照です。関数が作成されると、そのプロトタイプオブジェクトは、関数のプロトタイププロパティを介して作成およびリンクされます。コンストラクター関数を使用してオブジェクトを作成すると、コンストラクターのプロトタイプからプロパティとメソッドを継承します。ただし、ミキシンを使用して間接的に達成できます。ミックスインは、あるオブジェクトから別のオブジェクトにプロパティをコピーすることを含む手法です。これにより、オブジェクトは複数のソースからプロパティとメソッドを継承できます。クラス内のオブジェクトを作成および初期化するために使用される特別な方法。継承のコンテキストでは、サブクラスコンストラクターは、「この」キーワードを使用する前に「スーパー」キーワードを使用してスーパークラスコンストラクターを呼び出す必要があります。 > JavaScript ES2015の「Extends」キーワードは、スーパークラスからサブクラスを作成するために使用されます。サブクラスはスーパークラスのすべてのプロパティと方法を継承しますが、新しいものを追加したり、継承されたものをオーバーライドしたりすることもできます。 > JavaScriptでは、「クラス」とは、オブジェクトを作成するための青写真として使用される一種の関数です。そのデータで動作するデータと機能をカプセル化します。一方、「プロトタイプ」とは、他のオブジェクトがプロパティとメソッドを継承するオブジェクトです。サブクラスに同じ名前のメソッドを定義するだけで、サブクラスのメソッドをオーバーライドできます。サブクラスのインスタンスで呼び出されると、継承された方法の代わりに新しい方法が使用されます。 > JavaScriptの「新しい」キーワードを使用して、クラスまたはコンストラクター関数のインスタンスを作成します。継承のコンテキストでは、「新しい」キーワードを使用して、スーパークラスからプロパティとメソッドを継承するサブクラスのインスタンスを作成します。 >

JavaScriptでは、プロトタイプオブジェクトのプロパティに値を割り当てるだけで、オブジェクトのプロトタイプにプロパティを追加できます。このプロパティは、コンストラクター関数から作成されたすべてのオブジェクトによって継承されます。

以上がJavaScript ES2015のオブジェクト継承のパターンの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。