JavaScript中的工厂函数(推荐)

发布时间 - 2026-01-11 00:03:34    点击率:

在学习jQuery的时候,我们经常会看到“工厂函数”这个概念,那么究竟什么是“工厂函数”呢?我们来看看概念,“所谓工厂函数,就是指这些内建函数都是类对象,当你调用他们时,实际上是创建了一个类实例”。意思就是当我调用这个函数,实际上是先利用类创建了一个对象,然后返回这个对象。由于Javascript本身不是严格的面向对象的语言(不包含类),实际上来说,Javascript并没有严格的“工厂函数”,但是在Javascript中,我们能利用函数模拟类。

我们首先通过new关键字创建了一个对象,obj就相当于Object的实例。我们通过类实例化了一个对象,然后给这个对象相应的属性,最后返回对象。我们可以通过调用这个函数来创建对象,这样的话,实际上工厂函数也很好理解了:

1,它是一个函数。

2,它用来创建对象。

3,它像工厂一样,“生产”出来的函数都是“标准件”(拥有同样的属性)

不学习函数和对象,你不可能成为一名JavaScript程序员,并且当他们一起使用时,是构建块,我们需要从一个称为 组合(composition) 的强大对象范例开始。今天我们来看一些惯用的模式,使用工厂函数来组成函数,对象和 Promises 。组合模式是将一批子对象组织为树形结构,一条顶层的命令会在操作树中所有的对象。当一个函数返回一个对象时,我们称之他为 工厂函数(factory function) 。

    让我们来看一个简单的例子。

function createJelly() {
 return {
 type: 'jelly',
 colour: 'red'
 scoops: 3
 };
 }

下面我们通过一些实例给大家介绍。

    每次我们调用这个工厂函数,它将返回一个新的 jelly(果冻) 对象实例。要注意的重点是,我们不必在工厂函数名称前面加上 create ,但它可以让其他人更清楚函数的意图。对于 type 属性也是如此,但通常它可以帮助我们区分我们程序的对象。   

    1.带参数的工厂函数

    像所有函数一样,我们可以通过参数来定义我们的工厂函数 (icecream 冰淇淋),这可以用来改变返回对象的模型。

function createIceCream(flavour='Vanilla') {
 return {
 type: 'icecream',
 scoops: 3,
 flavour
 }
 }

    理论上,您可以使用带有数百个参数的工厂函数来返回非常特使的深层嵌套对象,但正如我们将看到的,这根本不是组合的精髓。

    2.组合的工厂函数

    在一个工厂函数中定义另一个工厂函数,可以帮助我们把复杂的工厂函数拆分成更小的,可重用的碎片。

    例如,我们可以创建一个 dessert(甜点)工厂函数,通过前面的 jelly(果冻)和 icecream(冰淇淋)工厂函数来定义。    

 function createDessert() {
 return {
 type: 'dessert',
 bowl: [
 createJelly(),
 createIceCream()
 ]
 };
 }

    我们可以组合工厂函数来构建任意复杂的对象,这不需要我们结合使用 new 或 this 。对象可以用 has-a (具有) 关系而不是 is-a (是) 来表示。也就是说,可以用组合而不是继承来实现。    

    例如,使用继承。

 // A trifle *is a* dessert 蛋糕*是*甜点
 function Trifle() {
 Dessert.apply(this, arguments);
 }
 Trifle.prototype = Dessert.prototype;
 // 或者
 class Trifle extends Dessert {
 constructor() {
 super();
 }
 }

   我们可以用组合模式表达相同的意思。

 // A trifle *has* layers of jelly, custard and cream. It also *has a* topping.
 // 蛋糕 *有* 果冻层,奶酪层和奶油层,顶部还 *有* 装饰配料。
 function createTrifle() {
 return {
 type: 'trifle',
 layers: [
 createJelly(),
 createCustard(),
 createCream()
 ],
 topping: createAlmonds()
 };
 }

    3.异步的工厂函数

    并非所有工厂都会立即返回数据。例如,有些必须先获取数据。在这些情况下,我们可以返回 Promises 来定义工厂函数。  

function getMeal(menuUrl) {
 return new Promise((resolve, reject) => {
 fetch(menuUrl)
 .then(result => {
 resolve({
 type: 'meal',
 courses: result.json()
 });
 })
 .catch(reject);
 });
 }

    这种深度嵌套的缩进会使异步工厂难以阅读和测试。将它们分解成多个不同的工厂通常是有帮助的,可以使用如下编写。

function getMeal(menuUrl) {
 return fetch(menuUrl)
 .then(result => result.json())
 .then(json => createMeal(json));
 }
 function createMeal(courses=[]) {
 return {
 type: 'meal',
 courses
 };
 }

    当然,我们可以使用回调函数,但是我们已经有了 Promise.all 这样的工具返回 Promises 来定义工厂函数。    

 function getWeeksMeals() {
 const menuUrl = 'jsfood.com/';
 return Promise.all([
 getMeal(`${menuUrl}/monday`),
 getMeal(`${menuUrl}/tuesday`),
 getMeal(`${menuUrl}/wednesday`),
 getMeal(`${menuUrl}/thursday`),
 getMeal(`${menuUrl}/friday`)
 ]);
 }

    我们使用 get 而不是 create 作为命名约定来显示这些工厂做一些异步工作和返回promise。

    4.函数和方法

    到目前为止,我们还没有看到任何工厂用方法返回对象,这是故意的。这是因为一般来说,我们不需要这么做。工厂允许我们从计算中分离我们的数据。这意味着我们总是能够将对象序列化为JSON,这对于在会话之间持久化,通过HTTP或WebSockets发送它们,并将它们放入数据存储很重要。

    例如,不是在 jelly(果冻) 对象上定义 eat 方法,我们可以定义一个新的函数,它接受一个对象作为参数并返回一个修改的版本。 

function eatJelly(jelly) {
 if(jelly.scoops > 0) {
 jelly.scoops -= 1;
 }
 return jelly;
 }

    一点点句法帮助使这是一个可行的模式,那些喜欢编程而不改变数据结构的人。对于那些喜欢编程而不改变数据结构的人来说,使用 ES6 的 ... 语法 是一个可行的模式。   

 function eat(jelly) {
 if(jelly.scoops > 0) {
 return { ...jelly, scoops: jelly.scoops - 1 };
 } else {
 return jelly;
 }
 }

    现在,不是这样写:

 import { createJelly } from './jelly';
 createJelly().eat();

    而是这样写   

 import { createJelly, eatJelly } from './jelly';
 eatJelly(createJelly()); 

 

    最终结果是一个函数,它接受一个对象并返回一个对象。我们称之为返回对象的函数是什么? 一个工厂!  

    5.高级工厂

    将工厂传递给 高阶函数 ,这将给我们带来巨大的控制力。例如,我们可以使用这个概念来创建一个增强的对象。   

 function giveTimestamp(factory) {
 return (...args) => {
 const instance = factory(...args);
 const time = Date.now();
 return { time, instance };
 };
 }
 const createOrder = giveTimestamp(function(ingredients) {
 return {
 type: 'order',
 ingredients
 };
 });

    这个增强的对象采用一个现有工厂,并将其包装以创建返回带有时间戳实例的工厂。或者,如果我们想要确保一个工厂返回不可变的对象,我们可以用 freezer 来增强它。    

 function freezer(factory) {
 return (...args) => Object.freeze(factory(...args)));
 }
 const createImmutableIceCream = freezer(createIceCream);
 createImmutableIceCream('strawberry').flavour = 'mint'; // Error!

    6.结论

    作为一个 聪明的程序员 曾经说过:从没有抽象比错误的抽象更容易回收。JavaScript项目有一个趋势,变得难以测试和重构,因为我们经常鼓励使用复杂的抽象层。原型和类实现一个简单的想法使用复杂和不人性的工具,如 new 和 this ,即使现在,这仍然引起 各种各样的困惑 -几年后他们被添加到语言。对象和函数对于来自大多数语言背景的程序员来说是有意义的,并且都是JavaScript中的原始类型,所以可以说工厂不是抽象的!对象和函数对来自大多数背景的程序员都有意义,并且都是JavaScript中的原始类型,所以可以说工厂不是抽象的!使用这些简单的构建块使得我们的代码对于没有经验的程序员更加友好,这绝对是我们应该关心的事情。工厂鼓励我们用原始数据来模拟复杂和异步数据,原始数据具有组合的自然能力,而不强迫我们去做一些高级抽象。 当我们坚持简单时,JavaScript更甜蜜!

以上所述是小编给大家介绍的JavaScript中的工厂函数,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!


# js工厂函数  # 详解Javascript 中的 class、构造函数、工厂函数  # javascript设计模式之对象工厂函数与构造函数详解  # JavaScript构造函数详解  # JS特殊函数(Function()构造函数、函数直接量)区别介绍  # JS面向对象基础讲解(工厂模式、构造函数模式、原型模式、混合模式、动态原型模式)  # JS中的构造函数详细解析  # 深入理解javascript构造函数和原型对象  # JavaScript中工厂函数与构造函数示例详解  # 我们可以  # 都是  # 可以用  # 而不  # 的人  # 是有  # 可以说  # 而不是  # 数据结构  # 给大家  # 可以使用  # 一个函数  # 中分  # 创建一个  # 小编  # 是一个  # 这是  # 原始数据  # 是在  # 都有 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 用yum安装MySQLdb模块的步骤方法  Win11怎么设置虚拟桌面 Win11新建多桌面切换操作【技巧】  如何在 Telegram Web View(iOS)中防止键盘遮挡底部输入框  详解CentOS6.5 安装 MySQL5.1.71的方法  Laravel怎么防止CSRF攻击_Laravel CSRF保护中间件原理与实践  DeepSeek是免费使用的吗 DeepSeek收费模式与Pro版本功能详解  Laravel如何处理CORS跨域请求?(配置示例)  JavaScript Ajax实现异步通信  手机网站制作平台,手机靓号代理商怎么制作属于自己的手机靓号网站?  ChatGPT 4.0官网入口地址 ChatGPT在线体验官网  Laravel怎么上传文件_Laravel图片上传及存储配置  如何在 Go 中优雅地映射具有动态字段的 JSON 对象到结构体  UC浏览器如何设置启动页 UC浏览器启动页设置方法  Laravel如何部署到服务器_线上部署Laravel项目的完整流程与步骤  浅述节点的创建及常见功能的实现  制作公司内部网站有哪些,内网如何建网站?  如何在Tomcat中配置并部署网站项目?  如何用PHP快速搭建高效网站?分步指南  Windows Hello人脸识别突然无法使用  iOS UIView常见属性方法小结  Laravel如何发送邮件和通知_Laravel邮件与通知系统发送步骤  如何快速使用云服务器搭建个人网站?  如何在万网开始建站?分步指南解析  HTML5空格和margin有啥区别_空格与外边距的使用场景【说明】  HTML5空格在Angular项目里怎么处理_Angular中空格的渲染问题【详解】  装修招标网站设计制作流程,装修招标流程?  使用spring连接及操作mongodb3.0实例  郑州企业网站制作公司,郑州招聘网站有哪些?  js实现获取鼠标当前的位置  Laravel如何自定义错误页面(404, 500)?(代码示例)  在线制作视频网站免费,都有哪些好的动漫网站?  Laravel API路由如何设计_Laravel构建RESTful API的路由最佳实践  网站制作软件有哪些,制图软件有哪些?  Laravel如何实现数据导出到CSV文件_Laravel原生流式输出大数据量CSV【方案】  Laravel中间件起什么作用_Laravel Middleware请求生命周期与自定义详解  jQuery中的100个技巧汇总  uc浏览器二维码扫描入口_uc浏览器扫码功能使用地址  Laravel怎么生成二维码图片_Laravel集成Simple-QrCode扩展包与参数设置【实战】  东莞市网站制作公司有哪些,东莞找工作用什么网站好?  Laravel怎么实现模型属性的自动加密  Laravel如何记录自定义日志?(Log频道配置)  微信小程序制作网站有哪些,微信小程序需要做网站吗?  php增删改查怎么学_零基础入门php数据库操作必知基础【教程】  如何安全更换建站之星模板并保留数据?  Laravel怎么做缓存_Laravel Cache系统提升应用速度的策略与技巧  php485函数参数是什么意思_php485各参数详细说明【介绍】  头像制作网站在线观看,除了站酷,还有哪些比较好的设计网站?  怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?  Laravel如何发送系统通知?(Notification渠道示例)  网站制作怎么样才能赚钱,用自己的电脑做服务器架设网站有什么利弊,能赚钱吗?