ES6 時代では、オブジェクトを作成する方法が増加し、さまざまなシナリオでオブジェクトを作成するためにさまざまな方法を選択できるようになりました。現在、オブジェクトを構築するには、クラス キーワード、コンストラクター、ファクトリ関数という 3 つの主な方法があります。これらはすべてオブジェクトを作成するための手段ですが、日々の開発ではこれらの違いに基づいて選択する必要もあります。この記事では主にJavaScriptのクラス、コンストラクタ、ファクトリ関数の詳細な説明を紹介しますので、必要な方は参考にしていただければ幸いです。
まず、これら 3 つのメソッドがどのようなものかを見てみましょう
// class 关键字,ES6新特性 class ClassCar { drive () { console.log('Vroom!'); } } const car1 = new ClassCar(); console.log(car1.drive()); // 构造函数 function ConstructorCar () {} ConstructorCar.prototype.drive = function () { console.log('Vroom!'); }; const car2 = new ConstructorCar(); console.log(car2.drive()); // 工厂函数 const proto = { drive () { console.log('Vroom!'); } }; function factoryCar () { return Object.create(proto); } const car3 = factoryCar(); console.log(car3.drive());
これらのメソッドはすべてプロトタイプの作成に基づいており、コンストラクター関数でのプライベート変数の実装をすべてサポートしています。言い換えれば、これらの関数はほとんど同じ特性を持ち、多くのシナリオで同等ですらあります。
JavaScript では、すべての関数が新しいオブジェクトを返すことができます。コンストラクターやクラスではない場合は、ファクトリ関数と呼ばれます。
ES6 クラスは実際にはコンストラクターの糖衣構文です (少なくともこの段階ではこれが実装されています)。そのため、次に説明する内容はすべてコンストラクターだけでなく ES6 クラスにも当てはまります:
class Foo {} console.log(typeof Foo); // function
構築 関数の利点ES6 クラス
ほとんどの本では、クラスとコンストラクターの使い方を教えています
「this」は新しいオブジェクトを指します。
新しいキーワードの読みやすさを好む人もいます
細部に若干の違いがあるかもしれませんが、開発プロセスに問題がない場合は、あまり心配しないでください。
コンストラクターとES6クラスのデメリット
1. 新しいキーワードが必要です
ES6では、コンストラクターとクラスの両方に新しいキーワードが必要です。
function Foo() { if (!(this instanceof Foo)) { return new Foo(); } }
ES6 では、new キーワードなしでクラス関数を呼び出そうとすると、タスクがスローされます。 new キーワードのないものが必要な場合は、ファクトリ関数を使用してラップするしかありません。
2. インスタンス化プロセス中の詳細は外部 API に公開されます
すべての呼び出しは、構築プロセス中に何かを行う必要がある場合、非常に面倒になります。
3. コンストラクターはオープン / クローズド ルールに準拠していません
新しいキーワードの詳細な処理のため、コンストラクターはオープン / クローズド ルールに違反しています。API は拡張に対してオープンであり、変更を避ける必要があります。
クラスとファクトリ関数は非常に似ており、クラス関数をファクトリ関数にアップグレードしても何の影響も与えないのではないかと疑問に思ったことがあるが、JavaScript では影響があります。
コンストラクターやクラスを書き始めたものの、書き続けるうちにファクトリ関数の柔軟性が必要になった場合、現時点では関数を変更してそのまま終了することはできません。
残念ながら、あなたは JavaScript プログラマーであり、コンストラクターをファクトリー関数に変換するのは大がかりな操作です:
// 原来的实现: // class Car { // drive () { // console.log('Vroom!'); // } // } // const AutoMaker = { Car }; // 工厂函数改变的实现: const AutoMaker = { Car (bundle) { return Object.create(this.bundle[bundle]); }, bundle: { premium: { drive () { console.log('Vrooom!'); }, getOptions: function () { return ['leather', 'wood', 'pearl']; } } } }; // 期望中的用法是: const newCar = AutoMaker.Car('premium'); newCar.drive(); // 'Vrooom!' // 但是因为他是一个库 // 许多地方依然这样用: const oldCar = new AutoMaker.Car(); // 如此就会导致: // TypeError: Cannot read property 'undefined' of // undefined at new AutoMaker.Car
上の例では、クラスから始めて、最終的にそれを使用できるクラスに変更しました。特定に基づくプロトタイプは、オブジェクトのファクトリー関数を作成するために使用されます。このような関数は、インターフェースの抽象化や特別なニーズのカスタマイズに広く使用できます。
4. コンストラクターを使用して、instanceof に機会を与える
コンストラクターとファクトリー関数の違いは、コードの正確性を保証するために、instanceof 演算子を使用することです。しかし、正直に言うと、これは非常に問題があるため、instanceof の使用を避けることをお勧めします。
インスタンスは嘘をつくことができます。
// instanceof 是一个原型链检查 // 不是一个类型检查 // 这意味着这个检查是取决于执行上下文的, // 当原型被动态的重新关联, // 你就会得到这样令人费解的情况 function foo() {} const bar = { a: 'a'}; foo.prototype = bar; // bar是一个foo的实例吗,显示不是 console.log(bar instanceof foo); // false // 上面我们看到了,他的确不是一个foo实例 // baz 显然也不是一个foo的实例,对吧? const baz = Object.create(bar); // ...不对. console.log(baz instanceof foo); // true. oops.
instanceof は、他の強く型付けされた言語のようなチェックは行わず、プロトタイプチェーン上のオブジェクトをチェックするだけです。
Constructor.prototypeを変更した場合など、一部の実行コンテキストでは無効となります。
もう 1 つの例は、コンストラクターまたはクラスから始めて、それを別のオブジェクトに展開する場合です。これは、ファクトリ関数として書き換えられる上記の状況とまったく同じです。現時点では、instanceof にも問題が発生します。
要約すると、instanceof はコンストラクターとファクトリー関数の呼び出しにおけるもう 1 つの大きな変更です。
クラスを使用する利点
便利な自己完結型キーワード
JavaScriptでクラスを実装する唯一の信頼できる方法。
クラス言語開発の経験がある他の開発者にとっては良い経験になります。
クラスを使用するデメリット
コンストラクターのすべてのデメリットに加えて:
extends キーワードを使用して問題のあるクラスを作成することは、ユーザーにとって大きな誘惑です。
クラスの階層的な継承は、断片化された基本クラス (継承により基本クラスが破壊される)、ゴリラバナナ問題 (複雑なコンテキストと混合されたオブジェクト)、必然的な重複 (次の場合にクラスを継承する必要がある) など、多くのよく知られた問題を引き起こします。多様化(随時変更)など。
他の 2 つの方法でもこれらの問題が発生する可能性がありますが、extend キーワードを使用すると、環境によってこのような問題が発生します。言い換えれば、再利用可能なコードではなく、柔軟性のない関係を持つコードを作成することになります。
ファクトリー関数を使用する利点
ファクトリー関数はクラスやコンストラクターよりも柔軟であり、人々を間違った道に導くことはありません。また、深い継承の連鎖に陥ることもありません。継承をシミュレートするために多くのメソッドを使用できます
1. 任意のプロトタイプを持つ任意のオブジェクトを返します
たとえば、同じ実装を通じて異なるインスタンスを作成したり、異なるメディア形式に合わせてメディア プレーヤーを作成したりできます。例:または、DOM イベントまたは ws イベント用のイベント ライブラリも考えられます。
ファクトリ関数は、実行コンテキストを通じてオブジェクトをインスタンス化することもでき、オブジェクト プールとより柔軟な継承モデルの恩恵を受けることができます。
2. 複雑なリファクタリングについて心配する必要はありません
ファクトリ関数をコンストラクターに変換する必要がないため、リファクタリングは必要ありません。
3. 新しいものはありません
新しいオブジェクトを作成するために new キーワードは必要ありません。このプロセスは自分でマスターできます。
4. 標準の this 動作
これはよく知られた this であり、親オブジェクトを取得するために使用できます。たとえば、player.create() では、this は player を指しますが、他の this は呼び出しと適用を通じてバインドすることもできます。
5. インスタンスオブでは問題ありません
6. 新しいものを使わずに直接書くことの読みやすさと直観性を好む人もいます。
ファクトリ関数の欠点
はプロトタイプを自動的に処理せず、ファクトリ関数プロトタイプはプロトタイプチェーンに影響を与えません。
これは、ファクトリ関数の新しいオブジェクトを自動的に指すわけではありません。
細部に若干の違いがあるかもしれませんが、開発過程で問題がなければ、あまり心配しないでください。
結論
私の意見では、クラスは便利なキーワードかもしれませんが、疑いを持たないユーザーを継承の穴に導くことは隠せません。もう 1 つのリスクは、将来ファクトリ関数を使用することになり、非常に大きな変更を加えなければならない可能性です。
比較的大規模なチームで作業している場合、パブリック API を変更する場合、アクセス権のないコードに干渉する可能性があるため、変更された関数の影響を無視することはできません。
ファクトリー パターンの優れた点の 1 つは、より強力で柔軟であるだけでなく、チーム全体が API をよりシンプル、安全、軽量にすることを奨励できることです。
関連する推奨事項:
JavaScript コンストラクターのこれと戻り値の詳細な紹介
JavaScript はオブジェクトを作成するためにファクトリ パターンとコンストラクターをどのように使用しますか?
JavaScriptの関数リテラルとFunction()コンストラクターの違いの詳細な説明
ファクトリモード、コンストラクターモード、プロトタイプモードを使用してJavaScriptでオブジェクトインスタンスを作成する方法
JavaScriptの式と構築基本チュートリアル機能の詳しい説明
以上がJavascriptのクラス、コンストラクタ、ファクトリ関数の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。