この記事では主に Javascript のクラス、コンストラクター、ファクトリー関数の詳細な説明を紹介します。必要な方は参考にしてください。
ES6 の時代では、オブジェクトを作成するメソッドが増え、さまざまなメソッドを選択できるようになりました。シナリオの作成方法。現在、オブジェクトを構築するには、クラス キーワード、コンストラクター、ファクトリ関数という 3 つの主な方法があります。これらはすべてオブジェクトを作成するための手段ですが、日々の開発ではこれらの違いに基づいて選択する必要もあります。
まず、これら 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 を使用しない場合
新しいオブジェクトを作成するために new キーワードは必要なく、このプロセスを自分で習得できます。
4. 標準の this 動作
これはよく知られた this であり、親オブジェクトを取得するために使用できます。たとえば、player.create() では、this は player を指しますが、他の this は呼び出しと適用を通じてバインドすることもできます。
5. インスタンスオブでは問題ありません
6. 新しいものを使わずに直接書くことの読みやすさと直観性を好む人もいます。
ファクトリ関数の欠点
はプロトタイプを自動的に処理せず、ファクトリ関数プロトタイプはプロトタイプチェーンに影響を与えません。
これは、ファクトリ関数の新しいオブジェクトを自動的に指すわけではありません。
細部に若干の違いがあるかもしれませんが、開発過程で問題がなければ、あまり心配しないでください。
結論
私の意見では、クラスは便利なキーワードかもしれませんが、疑いを持たないユーザーを継承の穴に導くことは隠せません。もう 1 つのリスクは、将来ファクトリ関数を使用することになり、非常に大きな変更を加えなければならない可能性です。
比較的大規模なチームで作業している場合、パブリック API を変更する場合、アクセス権のないコードに干渉する可能性があるため、変更された関数の影響を無視することはできません。
ファクトリー パターンの優れた点の 1 つは、より強力で柔軟であるだけでなく、チーム全体が API をよりシンプル、安全、軽量にすることを奨励できることです。
上記は私があなたのためにまとめたものです。
関連記事:
Reactコンポーネントの「外」で親コンポーネントを使用する方法の詳細な解釈
以上がJavascript でクラス、コンストラクター、ファクトリ関数を使用する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。