热门标签 | 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关键字。



推荐阅读
  • 本文介绍了绕过WAF的XSS检测机制的方法,包括确定payload结构、测试和混淆。同时提出了一种构建XSS payload的方法,该payload与安全机制使用的正则表达式不匹配。通过清理用户输入、转义输出、使用文档对象模型(DOM)接收器和源、实施适当的跨域资源共享(CORS)策略和其他安全策略,可以有效阻止XSS漏洞。但是,WAF或自定义过滤器仍然被广泛使用来增加安全性。本文的方法可以绕过这种安全机制,构建与正则表达式不匹配的XSS payload。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 本文比较了eBPF和WebAssembly作为云原生VM的特点和应用领域。eBPF作为运行在Linux内核中的轻量级代码执行沙箱,适用于网络或安全相关的任务;而WebAssembly作为图灵完备的语言,在商业应用中具有优势。同时,介绍了WebAssembly在Linux内核中运行的尝试以及基于LLVM的云原生WebAssembly编译器WasmEdge Runtime的案例,展示了WebAssembly作为原生应用程序的潜力。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 如何提高PHP编程技能及推荐高级教程
    本文介绍了如何提高PHP编程技能的方法,推荐了一些高级教程。学习任何一种编程语言都需要长期的坚持和不懈的努力,本文提醒读者要有足够的耐心和时间投入。通过实践操作学习,可以更好地理解和掌握PHP语言的特异性,特别是单引号和双引号的用法。同时,本文也指出了只走马观花看整体而不深入学习的学习方式无法真正掌握这门语言,建议读者要从整体来考虑局部,培养大局观。最后,本文提醒读者完成一个像模像样的网站需要付出更多的努力和实践。 ... [详细]
  • 本文详细介绍了云服务器API接口的概念和作用,以及如何使用API接口管理云上资源和开发应用程序。通过创建实例API、调整实例配置API、关闭实例API和退还实例API等功能,可以实现云服务器的创建、配置修改和销毁等操作。对于想要学习云服务器API接口的人来说,本文提供了详细的入门指南和使用方法。如果想进一步了解相关知识或阅读更多相关文章,请关注编程笔记行业资讯频道。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • Html5-Canvas实现简易的抽奖转盘效果
    本文介绍了如何使用Html5和Canvas标签来实现简易的抽奖转盘效果,同时使用了jQueryRotate.js旋转插件。文章中给出了主要的html和css代码,并展示了实现的基本效果。 ... [详细]
  • 单点登录原理及实现方案详解
    本文详细介绍了单点登录的原理及实现方案,其中包括共享Session的方式,以及基于Redis的Session共享方案。同时,还分享了作者在应用环境中所遇到的问题和经验,希望对读者有所帮助。 ... [详细]
  • 本文介绍了前端人员必须知道的三个问题,即前端都做哪些事、前端都需要哪些技术,以及前端的发展阶段。初级阶段包括HTML、CSS、JavaScript和jQuery的基础知识。进阶阶段涵盖了面向对象编程、响应式设计、Ajax、HTML5等新兴技术。高级阶段包括架构基础、模块化开发、预编译和前沿规范等内容。此外,还介绍了一些后端服务,如Node.js。 ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • JavaScript和HTML之间的交互是经由过程事宜完成的。事宜:文档或浏览器窗口中发作的一些特定的交互霎时。能够运用侦听器(或处置惩罚递次来预订事宜),以便事宜发作时实行相应的 ... [详细]
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社区 版权所有