构造函数与工厂函数

2020/11/07 17:22 · javascript ·  · 0评论

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

何时使用一个代替另一个?

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

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;
}

当然,您可以使工厂功能比该简单示例复杂得多。

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

使用构造函数的好处

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

  • this 指新对象

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

缺点

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

  • 忘记new是一个常见的错误,您应该强烈考虑添加样板检查,以确保正确调用了构造函数(if (!(this instanceof Foo)) { return new Foo() })。编辑:既然ES6(ES2015),你可别忘了newclass构造函数或构造函数将抛出一个错误。

  • 如果您进行instanceof检查,则对于是否new需要进行检查会产生歧义我认为不应该这样。您已经有效地缩短了new需求,这意味着您可以消除缺点1。但是,除了name之外,您几乎只有一个工厂函数,带有附加的样板,一个大写字母和较不灵活的this上下文。

构造函数违反了开放/封闭原则

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

但是,您被困住了。如果不破坏使用调用构造函数的所有代码,就无法进行更改new例如,您不能切换到使用对象池来提高性能。

同样,使用构造函数会给您一个欺骗性的效果instanceof这种欺骗性在跨执行上下文的情况下不起作用,并且如果您的构造函数原型被换出也不起作用。如果您开始this从构造函数返回,然后切换到导出任意对象,则必须执行此操作才能在构造函数中启用类似工厂的行为,这也会失败

使用工厂的好处

  • 代码更少-无需样板。

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

  • 您永远不需要从工厂转换为构造函数,因此重构永远不会成为问题。

  • 使用毫不含糊new别。(它将使this行为变差,请参阅下一点)。

  • this表现为它通常会-所以你可以用它来访问父对象(例如,内部的player.create()this指的是player,就像任何其他方法将调用callapply也重新分配this,如预期如果您存储父对象上的原型,即。可以很好地动态交换功能,并为对象实例化启用非常灵活的多态性。

  • 关于是否要大写没有歧义。别。棉绒工具会抱怨,然后您会尝试使用new,然后您将撤消上述好处。

  • 有些人喜欢阅读var myFoo = foo();var myFoo = foo.create();阅读。

缺点

  • new表现不符合预期(请参见上文)。解决方案:不要使用它。

  • this不引用新对象(相反,如果使用点符号或方括号符号调用构造函数,例如foo.bar()-this则与foo其他JavaScript方法一样引用-请参见好处)。

构造函数返回您调用的类的实例。工厂函数可以返回任何东西。当您需要返回任意值或类具有较大的设置过程时,可以使用工厂函数。

构造函数示例

function User(name) {
  this.name = name;
  this.isAdmin = false;
}

let user = new User("Jack");
  • new创建一个原型对象,User.prototypeUser使用创建的对象作为其this值进行调用

  • new 将其操作数的自变量表达式视为可选:

         let user = new User;
    

    会导致new调用User不带任何参数。

  • new返回它创建的对象,除非构造函数返回一个object value,而是返回它。这是一个边缘情况,在大多数情况下可以忽略。

利弊

由构造函数创建的对象从构造函数的prototype属性继承属性,并使用instanceOf构造函数上的运算符返回true

如果您prototype已经在使用构造函数后动态更改了构造函数的属性值,则上述行为可能会失败这样做很少见,如果使用class关键字创建了构造函数,则无法更改

可以使用extends关键字扩展构造函数

构造函数不能null作为错误值返回由于它不是对象数据类型,因此将被忽略new

工厂功能示例

function User(name, age) {
  return {
    name,
    age,
  }
};

let user = User("Tom", 23);

在这里,工厂函数不带new如果函数的参数及其返回的对象类型,则该函数完全负责直接或间接使用。在此示例中,它返回一个简单的[Object object],其中包含通过参数设置的某些属性。

利弊

轻松向调用者隐藏对象创建的实现复杂性。这对于浏览器中的本机代码功能特别有用。

工厂函数不必总是返回相同类型的对象,甚至可以null作为错误指示符返回

在简单的情况下,工厂功能的结构和含义可能很简单。

返回的对象通常不会从工厂函数的prototype属性继承,而false返回instanceOf factoryFunction

无法使用extends关键字安全地扩展工厂函数,因为扩展对象将继承自工厂函数prototype属性,而不是继承自工厂函数prototype使用的构造函数的属性

工厂“总是”更好。当使用面向对象的语言时

  1. 决定合同(方法和方法)
  2. 创建公开这些方法的接口(在javascript中,您没有接口,因此您需要提出一些检查实现的方法)
  3. 创建一个工厂,该工厂返回所需的每个接口的实现。

实现(使用new创建的实际对象)不会暴露给工厂用户/消费者。这意味着工厂开发人员可以在不违反合同的前提下扩展并创建新的实现...并且这允许工厂消费者仅从新API中受益而无需更改其代码...如果他们使用new并出现了“ new”实现,那么他们必须去更改每条使用“ new”的行以使用“ new”实现...对于工厂而言,其代码不会改变...

工厂-比其他所有工厂都要好-spring框架完全基于此思想构建的。

工厂是抽象的一层,就像所有抽象一样,它们也有一定的成本。遇到基于工厂的API时,弄清楚给定API的工厂对于API使用者而言可能是一个挑战。对于构造函数,可发现性是微不足道的。

在决策者和工厂之间做出决定时,您需要确定该好处是否证明了复杂性是合理的。

值得一提的是,通过返回除this或undefined以外的内容,Javascript构造函数可以是任意工厂。因此,在js中,您可以兼得两者-可发现的API和对象池/缓存。

对于差异,埃里克·埃利奥特(Eric Elliott)讲得很好,

但是对于第二个问题:

何时使用一个代替另一个?

如果您来自面向对象的背景,那么构造函数对您来说看起来更自然。这样,您就不会忘记使用new关键字。

本文地址:http://javascript.askforanswer.com/gouzaohanshuyugongchanghanshu.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!