ES6より前は、JavaScriptのファクトリ関数とコンストラクタ関数の違いについて多くの混乱がありました。 ES6には`class`キーワードがあるため、多くの人がコンストラクタ関数の多くの問題を解決したと考えているようです。 あなたがまだ気づく必要がある大きな違いを探ってみましょう。,
まず、それぞれの例を見てみましょう。
これらの戦略はそれぞれ、共有プロトタイプにメソッドを格納し、オプションでコンストラクタ関数クロージャを介してプライベートデータをサポートします。 言い換えれば、それらはほとんど同じ機能を持ち、ほとんど同じ意味で使用することができます。
JavaScriptでは、どの関数でも新しいオブジェクトを返すことができます。 コンストラクタ関数またはクラスでない場合は、ファクトリ関数と呼ばれます。,
ES6クラスはコンストラクタ関数にdesugarなので、コンストラクタ関数について次のすべてはES6クラスにも適用されます。
class Foo {}console.log(typeof Foo); // function
コンストラクタは呼び出し元にnew
キーワードを使用するよう強制します。 工場はそうではありませんそれはそれですが、それにはいくつかの関連する副作用がありまそれでは、new
キーワードは何をしますか?,
注:instance
を使用して新しく作成されたインスタンスを参照し、Constructor
インスタンスを作成したコンストラクタ関数またはクラスを参照します。
- 新しいインスタンスオブジェクトをインスタンス化し、
this
コンストラクタ内でそれにバインドします。
instance.__proto__
をConstructor.prototype
にバインドします。li>
- 2の副作用として、
instance.__proto__.constructor
をConstructor
にバインドします。,
- は暗黙的に
this
を返します。instance
を参照します。
コンストラクタの利点&`class`
- ほとんどの本では、クラスまたはコンストラクタを使用するように教えています。
this
新しいオブジェクトを参照します。li>
myFoo = new Foo()
の読み方が好きな人もいます。
- マイクロ最適化パフォーマンスの利点があるかもしれませんが、コードをプロファイリングして問題であることを証明しない限り、それについて心配すべきではありません。,
コンストラクタの欠点&`class`
ES6より前は、new
を忘れることは非常に一般的なバグでした。 これに対抗するために、多くの人が定型文を使用して強制しました。
function Foo() {
if (!(this instanceof Foo)) { return new Foo(); }
}
ES6+(ES2015)でnew
なしでクラスコンストラクタを呼び出そうとすると、常にエラーがスローされます。 ファクトリ関数でクラスをラップせずに呼び出し元にnew
要件を強制することを避けることはできません。,
インスタンス化の詳細は、呼び出し元のAPIに(”新しい”要件を介して)漏洩します。
すべての呼び出し元は、コンストラクタの実装に密接に結合されています。 工場のさらなる柔軟性が必要な場合、リファクタリングは画期的な変更です。 クラスからファクトリへのリファクタリングは、Martin Fowler、Kent Beck、John Brant、William Opdyke、およびDon Robertsによる独創的なリファクタリングの本”Refactoring:Improving the Design of Existing Code”に登場するほど一般的です。,
コンストラクタはオープン/クローズの原則を破ります
new
要件のため、コンストラクタ関数はオープン/クローズの原則に違反します。APIは拡張のために開いている必要がありますが、変更のために閉じている必要があります。
私は、クラスからファクトリへのリファクタリングは、すべてのコンストラクタの標準拡張とみなされるべきであると主張しています。,
コンストラクターまたはクラスのエクスポートを開始し、ユーザーがコンストラクターを使用し始めると、ファクトリーの柔軟性が必要になります(たとえば、実装をオブジェクトプールを使用するように切り替えたり、実行コンテキスト間でインスタンス化したり、代替プロトタイプを使用して継承の柔軟性を高めたりするなど)。,
残念ながら、JavaScriptでは、コンストラクタまたはクラスからファクトリに切り替えることは重大な変更です。