热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:构造函数vs工厂函数

篇首语:本文由编程笔记#小编为大家整理,主要介绍了构造函数vs工厂函数相关的知识,希望对你有一定的参考价值。

篇首语:本文由编程笔记#小编为大家整理,主要介绍了构造函数vs工厂函数相关的知识,希望对你有一定的参考价值。



有人可以澄清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(编辑:这可能是一个问题,因为如果没有new,该功能仍将运行但不如预期的那样)。我不认为这是一个优势:new是语言的核心部分,所以对我来说故意避免它有点武断 - 可能还要避免像else这样的其他关键词。

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


另一答案

Benefits of using constructors

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

  • this指的是新的对象

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


Drawbacks

  • 实例化的细节被泄漏到调用API中(通过new要求),因此所有调用者都与构造函数实现紧密耦合。如果您需要工厂的额外灵活性,您将不得不重构所有呼叫者(无可否认的是例外情况,而不是规则)。

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

  • 如果你做instanceof检查,它是否需要new模糊不清。在我看来,它不应该。你已经有效地缩短了new的要求,这意味着你可以消除缺点#1。但是,除了名称之外,你只有一个工厂函数,还有额外的样板,大写字母和不太灵活的this上下文。


构造函数打破了开放/封闭原则

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

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

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


Benefits of using factories

  • 更少的代码 - 无需样板。

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

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

  • 没有关于使用new的歧义。别。 (这将使this表现得很糟糕,见下一点)。

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

  • 没有关于是否资本化的含糊不清。别。 Lint工具会抱怨,然后你会试图尝试使用new,然后你将撤消上述的好处。

  • 有些人喜欢var myFoo = foo();var myFoo = foo.create();读取的方式。


Drawbacks

  • new表现不尽如人意(见上文)。解决方案:不要使用它。

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


另一答案

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


另一答案

一个构造函数的例子

function User(name) {
this.name = name;
this.isAdmin = false;
}
let user = new User("Jack");


  • newUser.prototype上创建一个原型对象,并将创建的对象调用User作为其this值。

  • new将其操作数的参数表达式视为可选:
    let user = new User;

    会导致new没有参数调用User

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


Pros and Cons

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

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

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

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


工厂功能示例

function User(name, age) {
return {
name,
age,
}
};
let user = User("Tom", 23);

这里没有new调用工厂函数。如果函数的参数和它返回的对象类型,该函数完全负责直接或间接使用。在这个例子中,它返回一个简单的[Object object],其中一些属性是从arguments设置的。


Pros and Cons

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

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

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

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

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


另一答案

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



  1. 决定合同(方法和他们将做什么)

  2. 创建暴露这些方法的接口(在Javascript中你没有接口,所以你需要提出一些检查实现的方法)

  3. 创建一个工厂,返回所需的每个接口的实现。

实现(使用new创建的实际对象)不会向工厂用户/使用者公开。这意味着工厂开发人员可以扩展并创建新的实现,只要他/她不违反合同......并且它允许工厂消费者只需从新API中受益而无需更改其代码......如果他们使用新的和“新的”实现出现然后他们必须去改变使用“新”的每一行使用“新”实现...与工厂他们的代码不会改变...

工厂 - 比其他任何东西都更好 - 弹簧框架完全围绕这个想法。


另一答案

工厂是一个抽象层,就像所有抽象一样,它们具有复杂性。当遇到基于工厂的API时,确定给定API的工厂是什么对API消费者来说可能是一个挑战。对于构造函数,可发现性是微不足道的。

在决策者和工厂之间做出决定时,您需要确定复杂性是否符合效益。

值得注意的是,Javascript构造函数可以通过返回除此之外或未定义的内容而成为任意工厂。所以在js中你可以充分利用这两个世界 - 可发现的API和对象池/缓存。


另一答案

对于差异,Eric Elliott澄清得很清楚,

但对于第二个问题:



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


如果您来自面向对象的背景,Constructor函数看起来更自然。这样你就不应该忘记使用new关键字。



推荐阅读
  • 本文详细介绍了Java代码分层的基本概念和常见分层模式,特别是MVC模式。同时探讨了不同项目需求下的分层策略,帮助读者更好地理解和应用Java分层思想。 ... [详细]
  • 本文详细介绍了Java反射机制的基本概念、获取Class对象的方法、反射的主要功能及其在实际开发中的应用。通过具体示例,帮助读者更好地理解和使用Java反射。 ... [详细]
  • 重要知识点有:函数参数默许值、盈余参数、扩大运算符、new.target属性、块级函数、箭头函数以及尾挪用优化《深切明白ES6》笔记目次函数的默许参数在ES5中,我们给函数传参数, ... [详细]
  • 本文总结了Java初学者需要掌握的六大核心知识点,帮助你更好地理解和应用Java编程。无论你是刚刚入门还是希望巩固基础,这些知识点都是必不可少的。 ... [详细]
  • 本文详细介绍了如何解决DNS服务器配置转发无法解析的问题,包括编辑主配置文件和重启域名服务的具体步骤。 ... [详细]
  • 原文网址:https:www.cnblogs.comysoceanp7476379.html目录1、AOP什么?2、需求3、解决办法1:使用静态代理4 ... [详细]
  • 深入解析 Lifecycle 的实现原理
    本文将详细介绍 Android Jetpack 中 Lifecycle 组件的实现原理,帮助开发者更好地理解和使用 Lifecycle,避免常见的内存泄漏问题。 ... [详细]
  • 解决Bootstrap DataTable Ajax请求重复问题
    在最近的一个项目中,我们使用了JQuery DataTable进行数据展示,虽然使用起来非常方便,但在测试过程中发现了一个问题:当查询条件改变时,有时查询结果的数据不正确。通过FireBug调试发现,点击搜索按钮时,会发送两次Ajax请求,一次是原条件的请求,一次是新条件的请求。 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 单元测试:使用mocha和should.js搭建nodejs的单元测试
    2019独角兽企业重金招聘Python工程师标准BDD测试利器:mochashould.js众所周知对于任何一个项目来说,做好单元测试都是必不可少 ... [详细]
  • 秒建一个后台管理系统?用这5个开源免费的Java项目就够了
    秒建一个后台管理系统?用这5个开源免费的Java项目就够了 ... [详细]
  • Python 数据可视化实战指南
    本文详细介绍如何使用 Python 进行数据可视化,涵盖从环境搭建到具体实例的全过程。 ... [详细]
  • 本文最初发表在Thorben Janssen的Java EE博客上,每周都会分享最新的Java新闻和动态。 ... [详细]
  • 网站访问全流程解析
    本文详细介绍了从用户在浏览器中输入一个域名(如www.yy.com)到页面完全展示的整个过程,包括DNS解析、TCP连接、请求响应等多个步骤。 ... [详细]
  • 装饰者模式(Decorator):一种灵活的对象结构设计模式
    装饰者模式(Decorator)是一种灵活的对象结构设计模式,旨在为单个对象动态地添加功能,而无需修改原有类的结构。通过封装对象并提供额外的行为,装饰者模式比传统的继承方式更加灵活和可扩展。例如,可以在运行时为特定对象添加边框或滚动条等特性,而不会影响其他对象。这种模式特别适用于需要在不同情况下动态组合功能的场景。 ... [详细]
author-avatar
钟孝健V
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有