ホームページ > 記事 > ウェブフロントエンド > JavaScript オブジェクトの作成パターンとベスト プラクティス
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 类,用新语法来实现上述功能要简洁得多。
class Thing { constructor() { this.x = 42; this.y = 3.14; } f() {} g() {} } var o = new Thing();
多年以来,JavaScript开发者们与原型链的关系总是若即若离,纠缠不清。而今天我们最有可能遇到的两种创建对象的方式,一种是强烈依赖原型链的class语法,另一种则是完全不依赖原型链的工厂函数语法。这两种方式在性能上和特点上是不一样的——尽管差别不太大。
今天的JavaScript引擎已经经过了大幅度的优化,以至于很难通过JavaScript代码来推断怎样会比较快。关键在于测量方法。然而测量方法有时也会失灵。通常每六周就会有更新的JavaScript引擎发布,而在这之前采取的测量方法,和基于这种测量方法做出的决策都有可能失去意义。因此,我的经验法则是选择最官方、最广泛使用的语法,因为大多数时候它经历的实践检验最多,因而性能是最高的。目前来说class语法最符合这一点,在我写这篇文章时,class语法大约比返回字面量的工厂函数快3倍。
随着ES6的发布,类与工厂函数之间曾经存在的几点差异消失了。现在,工厂函数和类都能够强制实现真正的私有数据——工厂函数通过闭包实现,类通过WeakMap实现。两者都能实现多重继承——工厂函数可以将其他属性混入自己的对象,类也可以将其他属性混入自己的原型,或者通过类工厂,通过代理也能实现。工厂函数和类也都可以在需要的时候返回任意对象,语法也都很简单。
综合考虑,我更倾向于class语法。它标准、简单、干净、快速,还提供了所有曾经只有函数工厂才具备的特点。
以上就是JavaScript 创建对象模式与最佳实践的内容,更多相关内容请关注PHP中文网(www.php.cn)!