构造函数与工厂函数使用构造函数的好处缺点使用工厂的好处缺点

2022-08-30 01:48:49

有人可以澄清Javascript中构造函数和工厂函数之间的区别吗?

何时使用一个而不是另一个?


答案 1

基本区别在于构造函数与关键字一起使用(这会导致JavaScript自动创建一个新对象,在函数中设置为该对象,然后返回该对象):newthis

var objFromConstructor = new ConstructorFunction();

工厂函数像“常规”函数一样调用:

var objFromFactory = factoryFunction();

但是,要将其视为“工厂”,它需要返回某个对象的新实例:如果它只是返回布尔值或其他东西,则不会将其称为“工厂”函数。这不会像 一样自动发生,但它确实允许在某些情况下具有更大的灵活性。new

在一个非常简单的示例中,上面引用的函数可能如下所示:

function ConstructorFunction() {
   this.someProp1 = "1";
   this.someProp2 = "2";
}
ConstructorFunction.prototype.someMethod = function() { /* whatever */ };

function factoryFunction() {
   var obj = {
      someProp1 : "1",
      someProp2 : "2",
      someMethod: function() { /* whatever */ }
   };
   // other code to manipulate obj in some way here
   return obj;
}

当然,你可以使工厂函数比这个简单的例子复杂得多。

工厂函数的一个优点是,根据某些参数,要返回的对象可能属于几种不同的类型。


答案 2

使用构造函数的好处

  • 大多数书籍教你使用构造函数和new

  • this引用新对象

  • 有些人喜欢阅读方式。var myFoo = new Foo();

缺点

  • 实例化的详细信息(通过要求)泄漏到调用 API 中,因此所有调用方都与构造函数实现紧密耦合。如果你需要工厂的额外灵活性,你必须重构所有调用方(诚然,这是例外情况,而不是规则)。new

  • 忘记是一个常见的错误,您应该强烈考虑添加样板检查,以确保正确调用构造函数( )。编辑:从ES6(ES2015)开始,你不能忘记构造函数,否则构造函数会抛出错误。newif (!(this instanceof Foo)) { return new Foo() }newclass

  • 如果您进行检查,则会在是否需要检查时留下歧义。在我看来,它不应该是。您已经有效地使要求短路,这意味着您可以消除缺点#1。但是,除了名称之外,你只有一个工厂函数,有额外的样板,大写字母和不太灵活的上下文。instanceofnewnewthis

构造函数打破开/闭原理

但我主要担心的是,它违反了开放/封闭原则。您从导出构造函数开始,用户开始使用构造函数,然后您意识到您需要工厂的灵活性(例如,将实现切换为使用对象池,或跨执行上下文实例化,或使用原型OO具有更大的继承灵活性)。

不过,你被困住了。如果不中断使用 调用构造函数的所有代码,就无法进行更改。例如,您不能为了提高性能而改用对象池。new

此外,使用构造函数会给你一个欺骗性,它不能跨执行上下文工作,如果你的构造函数原型被交换出来,它就不起作用。如果您从构造函数开始返回,然后切换到导出任意对象,那么它也将失败,您必须执行此操作才能在构造函数中启用类似工厂的行为。instanceofthis

使用工厂的好处

  • 更少的代码 - 不需要样板。

  • 您可以返回任何任意对象,并使用任意原型 - 让您更灵活地创建实现相同API的各种类型的对象。例如,可以同时创建 HTML5 和 flash 播放器实例的媒体播放器,或者可以发出 DOM 事件或 Web 套接字事件的事件库。工厂还可以跨执行上下文实例化对象,利用对象池,并允许更灵活的原型继承模型。

  • 你永远不需要从工厂转换为构造函数,所以重构永远不会成为问题。

  • 使用 没有歧义。不要。(这将使行为变得糟糕,请参阅下一点)。newthis

  • this行为正常 - 因此您可以使用它来访问父对象(例如,在 内部 ,引用 ,就像任何其他方法调用一样。 并且还按预期重新分配。如果将原型存储在父对象上,这可能是动态交换功能并为对象实例化启用非常灵活的多态性的好方法。player.create()thisplayercallapplythis

  • 关于是否大写没有歧义。不要。Lint 工具会抱怨,然后你会忍不住尝试使用 ,然后你会撤消上述好处。new

  • 有些人喜欢这种方式或阅读方式。var myFoo = foo();var myFoo = foo.create();

缺点

  • new行为不符合预期(见上文)。解决方案:不要使用它。

  • this不引用新对象(相反,如果构造函数是用点表示法或方括号表示法调用的,例如 foo.bar() - 引用 - 就像所有其他JavaScript方法一样 - 看到好处)。thisfoo