プロトタイプはオブジェクトです(そしてそれが重要な理由)

JavaScriptは、Hexletのスタックの主要言語の1つです。 プラットフォームのインタラクティブな部分でReactJSとNodeJSを使用し、 入門コース (より高度-進行中)を実施しました。 JSへの愛は、優れたエッセイである「プロトタイプはオブジェクトである」(およびそれが重要な理由)のこの翻訳の発行を支援しました。



この投稿は、JavaScriptのオブジェクトに精通しており、プロトタイプがオブジェクトの動作を定義する方法、コンストラクター関数とは何か、そしてコンストラクターの.propertyプロパティが構築するオブジェクトを参照する方法を知っている人を対象としています。 ECMAScript 2015構文の一般的な理解も害になりません。



JavaScriptでこの方法でクラスをいつでも作成できます。



function Person (first, last) { this.rename(first, last); } Person.prototype.fullName = function fullName () { return this.firstName + " " + this.lastName; }; Person.prototype.rename = function rename (first, last) { this.firstName = first; this.lastName = last; return this; }
      
      







Personはコンストラクター関数であり、JavaScriptの意味でのクラスです。 ECMAScript 2015では、 classキーワードなどを使用できます。 「コンパクトなメソッド表記」。 これは、関数を作成し、そのプロトタイプにメソッドを割り当てるための構文上の砂糖です(すべてが少し複雑になっていますが、今では重要ではありません)。 したがって、次のようにPersonクラスを記述できます。



 class Person { constructor (first, last) { this.rename(first, last); } fullName () { return this.firstName + " " + this.lastName; } rename (first, last) { this.firstName = first; this.lastName = last; return this; } };
      
      







かっこいい。 しかし、 内部ではまだPerson名にバインドされたコンストラクター関数があり、次のようなPerson.prototypeオブジェクトがあります。



 { fullName: function fullName () { return this.firstName + " " + this.lastName; }, rename: function rename (first, last) { this.firstName = first; this.lastName = last; return this; } }
      
      







プロトタイプはオブジェクトです


JavaScriptでオブジェクトの動作を変更する必要がある場合、このオブジェクトのプロパティに関連付けられた関数を追加、削除、または変更することにより、オブジェクトのメソッドを追加、削除、または変更できます。 これは、メソッドを定義するための特別な形式(たとえば、Rubyにはdefがあります)がある多くの「古典的な」言語とは対照的です。



JavaScriptのプロトタイプは「単なるオブジェクト」であるため、このプロトタイプのプロパティにバインドされている関数を追加、削除、または変更することにより、プロトタイプメソッドを追加、削除、または変更できます。



これがまさにECMAScript 5が上記のコードを作成し、クラス構文がそれを同等のコードに「開く」ことです。



プロトタイプは「単なるオブジェクト」であり、これは、オブジェクトに対して機能する任意の手法を使用できることを意味します。 たとえば、1つの関数をプロトタイプにバインドする代わりに、 Object.assignを使用して一括バインドを行うことができます。



 function Person (first, last) { this.rename(first, last); } Object.assign(Person.prototype, { fullName: function fullName () { return this.firstName + " " + this.lastName; }, rename: function rename (first, last) { this.firstName = first; this.lastName = last; return this; } })
      
      







そして、もちろん、必要に応じてコンパクトな構文を使用できます。



 function Person (first, last) { this.rename(first, last); } Object.assign(Person.prototype, { fullName () { return this.firstName + " " + this.lastName; }, rename (first, last) { this.firstName = first; this.lastName = last; return this; } })
      
      







ミックスイン(不純物)


このクラスはコードをコンストラクター関数とプロトタイプに「拡張」するため、次のような不純物を使用できます。



 class Person { constructor (first, last) { this.rename(first, last); } fullName () { return this.firstName + " " + this.lastName; } rename (first, last) { this.firstName = first; this.lastName = last; return this; } }; Object.assign(Person.prototype, { addToCollection (name) { this.collection().push(name); return this; }, collection () { return this._collected_books || (this._collected_books = []); } })
      
      







Personクラスの本を収集するメソッドに「干渉」しました。 コードを書くだけでいいのですが、名前を付けることもできます。



 const BookCollector = { addToCollection (name) { this.collection().push(name); return this; }, collection () { return this._collected_books || (this._collected_books = []); } }; class Person { constructor (first, last) { this.rename(first, last); } fullName () { return this.firstName + " " + this.lastName; } rename (first, last) { this.firstName = first; this.lastName = last; return this; } }; Object.assign(Person.prototype, BookCollector);
      
      







したがって、必要な限り続行できます。



 const BookCollector = { addToCollection (name) { this.collection().push(name); return this; }, collection () { return this._collected_books || (this._collected_books = []); } }; const Author = { writeBook (name) { this.books().push(name); return this; }, books () { return this._books_written || (this._books_written = []); } }; class Person { constructor (first, last) { this.rename(first, last); } fullName () { return this.firstName + " " + this.lastName; } rename (first, last) { this.firstName = first; this.lastName = last; return this; } }; Object.assign(Person.prototype, BookCollector, Author);
      
      







不純物を使用する理由


基本機能(Person)とミックスイン(BookCollectorおよびAuthor)でクラスをアセンブルすると、いくつかの利点があります。 まず、機能を美しいツリー構造に簡単に分解できない場合があります。 本の著者は企業ではなく、人かもしれません。 そして、アンティークの本屋は本好きのように本を集めます。



BookCollectorAuthorなどの不純物は、いくつかの異なるクラスで干渉される可能性があります。 継承を使用して機能を構成する試みは、常に成功するとは限りません。



別の利点は単純な例ではそれほど明白ではありませんが、実稼働システムのクラスはとんでもないサイズに成長する可能性があります。 混合物がいくつかのクラスで使用されない場合でも、不純物を使用する大規模なクラスの分解は、 唯一の義務の原則の原則を満たすのに役立ちます。 各ミックスインには1つの責任領域のみを設定できます。 これにより、理解とテストが簡単になります。

なぜそれが重要なのですか



責任をクラスに分解する他の方法(委任や構成など)がありますが、要点は、ミックスインを使用することに決めた場合、JavaScriptには明確にさせる大規模で複雑なOOPメカニズムがないため、これは非常に簡単な方法ですフレームワーク。



たとえば、Rubyはミックスインを簡単に使用します。なぜなら、最初からモジュールという特別な機能があるからです。 他のオブジェクト指向言語では、クラスシステムがそれらをサポートせず、メタプログラミングに実際には適合しないため、ミックスインを使用することは困難です。



All Articles