JavaScript での「オブジェクトの作成」は複雑なトピックです。この言語にはオブジェクトを作成するためのさまざまな方法が用意されているため、初心者も経験豊富なユーザーもどれを選択すればよいか混乱するかもしれません。ただし、オブジェクトを作成する方法はたくさんあり、構文は非常に異なっているように見えますが、実際には思っているより似ている可能性があります。この記事では、オブジェクト作成メソッドを整理する旅にあなたを導き、さまざまなメソッド間の依存関係と漸進的な関係を明らかにします。
最初に取り組むのは、間違いなくオブジェクト、オブジェクト リテラルを作成する最も簡単な方法です。 JavaScript は常に、クラスもテンプレートもプロトタイプも必要とせず、「何もないところから」オブジェクトを作成できると説いており、メソッドとデータを備えたオブジェクトが「ポップ」で表示されます。
var o = { x: 42, y: 3.14, f: function() {}, g: function() {} };
しかし、この方法には欠点があります。同じタイプのオブジェクトを別の場所に作成したい場合は、このオブジェクトのメソッド、データ、初期化をコピーして貼り付ける必要があります。同じタイプのオブジェクトを 1 つだけではなくバッチで作成する方法が必要です。
次の目的地はファクトリー関数です。明らかに、このメソッドを使用して、同じ構造、インターフェイス、実装を持つオブジェクトのクラスを作成するのが最も簡単です。オブジェクト リテラルを直接作成するのではなく、同じ型のオブジェクトを複数回または複数の場所に作成する必要がある場合は、この関数を呼び出すだけで済みます。
function thing() { return { x: 42, y: 3.14, f: function() {}, g: function() {} }; } var o = thing();
しかし、このアプローチには欠点もあります。各オブジェクトにはファクトリ関数の独立したコピーが含まれるため、メモリの肥大化が発生します。理論的には、すべてのオブジェクトがファクトリ関数のコピーを共有するようにします。
JavaScript は、プロトタイプ チェーンと呼ばれる、オブジェクト間でデータを共有するための組み込みメカニズムを提供します。オブジェクトのプロパティにアクセスすると、リクエストを完了するために他のオブジェクトに委任されます。これを使用してファクトリ関数を変更し、作成される各オブジェクトに独自の一意のデータのみが含まれるようにし、他のプロパティに対するリクエストはすべてプロトタイプ チェーン上の共通オブジェクトに委任できます。
var thingPrototype = { f: function() {}, g: function() {} }; function thing() { var o = Object.create(thingPrototype); o.x = 42; o.y = 3.14; return o; } var o = thing();
実際、JavaScript 自体には、この一般的なパターンをサポートするメカニズムが組み込まれています。この共有オブジェクト (プロトタイプ オブジェクト) を自分で作成する必要はありません。JavaScript によって関数ごとにプロトタイプ オブジェクトが自動的に作成され、このオブジェクトに共有データを直接配置できます。
thing.prototype.f = function() {}; thing.prototype.g = function() {}; function thing() { var o = Object.create(thing.prototype); o.x = 42; o.y = 3.14; return o; } var o = thing();
しかし、この方法には欠点もあります。それは重複が発生するということです。上記の Thing 関数の最初と最後の行は、すべての「デリゲート プロトタイプのファクトリ関数」で、ほとんど違いなく繰り返されます。
これらの繰り返しコードを抽出してカスタム関数に入れることができます。この関数はオブジェクトを作成し、他の任意の関数 (パラメータ関数) のプロトタイプと委任 (継承) 関係を確立します。次に、新しく作成したオブジェクトをパラメータとして使用し、この関数 (パラメータ関数) を呼び出し、最後にこれを返します。新しいオブジェクト。
function create(fn) { var o = Object.create(fn.prototype); fn.call(o); return o; } // ... Thing.prototype.f = function() {}; Thing.prototype.g = function() {}; function Thing() { this.x = 42; this.y = 3.14; } var o = create(Thing);
実際、JavaScript にもこのメソッドのサポートが組み込まれています。私たちが定義した create 関数は、実際には new キーワードの基本的な実装であるため、create を new に簡単に置き換えることができます。
rreee私たちが到着した駅は、ES5クラスと呼ばれることが多いです。関数を通じてオブジェクトを作成し、共有する必要があるデータをプロトタイプ オブジェクトに委任し、new キーワードを使用して繰り返しロジックを処理します。
しかし、この方法には欠点もあります。冗長で見苦しく、継承を実装するとさらに冗長で見苦しくなります。
JavaScript の最新の関連改善は ES6 クラスで、新しい構文を使用して上記の関数を実装するのがはるかに簡単です。
Thing.prototype.f = function() {}; Thing.prototype.g = function() {}; function Thing() { this.x = 42; this.y = 3.14; } var o = new Thing();
長年にわたり、JavaScript 開発者とプロトタイプ チェーンとの関係は常に曖昧でした。現在私たちが遭遇する可能性が最も高い 2 つの方法は、プロトタイプ チェーンに大きく依存するクラス構文であり、もう 1 つはプロトタイプ チェーンにまったく依存しないファクトリ関数構文です。 2 つの方法はパフォーマンスと機能の点で異なりますが、その違いはそれほど大きくありません。
今日の JavaScript エンジンは大幅に最適化されているため、JavaScript コードから何が高速になるかを推測するのは困難です。鍵は測定方法にあります。しかし、測定方法が失敗することもあります。更新された JavaScript エンジンは通常 6 週間ごとにリリースされ、それまでに行われた測定や、その測定に基づいて行われた決定は無意味になる可能性があります。したがって、私の経験則では、最も公式で広く使用されている構文を選択することになります。これは、ほとんどの場合、実際に最も多くテストされており、パフォーマンスが最も高いためです。現時点ではクラス構文がこれに最適であり、この記事を書いている時点では、クラス構文はリテラルを返すファクトリ関数よりも約 3 倍高速です。
ES6 のリリースにより、クラスとファクトリー関数の間にかつて存在していたいくつかの違いがなくなりました。ファクトリ関数とクラスの両方が真のプライベート データを強制できるようになりました。ファクトリ関数は クロージャ を介して、クラスは WeakMap を介して適用されます。どちらも多重継承を実装できます。ファクトリ関数は他のプロパティを独自のオブジェクトに混合でき、クラスは他のプロパティを独自のプロトタイプに、クラス ファクトリやプロキシを介して混合できます。ファクトリ関数とクラスは、必要に応じて任意のオブジェクトを返すこともでき、構文は非常に単純です。
すべてを考慮すると、私はクラス構文を好みます。これは標準的、シンプル、クリーン、高速であり、かつてはファンクション ファクトリでのみ利用可能だったすべての機能を提供します。
上記は、JavaScript 作成オブジェクト パターンのコード例とベスト プラクティスの詳細な説明です。その他の関連コンテンツについては、PHP 中国語 Web サイト (www.php.cn) に注目してください。