JavaScript中的工厂函数(推荐)


Posted in Javascript onMarch 08, 2017

JavaScript中的工厂函数(推荐)

在学习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中的工厂函数,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
JavaScript中isPrototypeOf函数作用和使用实例
Jun 01 Javascript
信息页文内画中画广告js实现代码(文中加载广告方式)
Jan 03 Javascript
jQuery Mobile操作HTML5的常用函数总结
May 17 Javascript
详解JavaScript中this关键字的用法
May 26 Javascript
AngularJS入门教程之数据绑定原理详解
Nov 02 Javascript
AngularJS指令与控制器之间的交互功能示例
Dec 14 Javascript
jQuery中DOM节点删除之empty与remove
Jan 20 Javascript
JavaScript实现获取select下拉框中第一个值的方法
Feb 06 Javascript
vue3.0 CLI - 2.4 - 新组件 Forms.vue 中学习表单
Sep 14 Javascript
原生JS实现自定义下拉单选选择框功能
Oct 12 Javascript
微信小程序新手教程之页面打开数量限制
Mar 03 Javascript
SSM VUE Axios详解
Oct 05 Vue.js
老生常谈js中0到底是 true 还是 false
Mar 08 #Javascript
jQuery插件zTree实现更新根节点中第i个节点名称的方法示例
Mar 08 #Javascript
JS字符串false转boolean的方法(推荐)
Mar 08 #Javascript
原生js实现选项卡功能
Mar 08 #Javascript
js, jQuery实现全选、反选功能
Mar 08 #Javascript
基于JQuery的购物车添加删除以及结算功能示例
Mar 08 #Javascript
jQuery插件zTree实现单独选中根节点中第一个节点示例
Mar 08 #Javascript
You might like
PHP 数组遍历方法大全(foreach,list,each)
2010/06/30 PHP
php利用新浪接口查询ip获取地理位置示例
2014/01/20 PHP
PHP7.0安装笔记整理
2015/08/28 PHP
浅谈PHP中pack、unpack的详细用法
2018/03/12 PHP
php依赖注入知识点详解
2019/09/23 PHP
javascript入门·图片对象(无刷新变换图片)\滚动图像
2007/10/01 Javascript
input的focus方法使用
2010/03/13 Javascript
心扬JS分页函数代码
2010/09/10 Javascript
拖动布局之保存布局页面cookies篇
2010/10/29 Javascript
读jQuery之九 一些瑕疵说明
2011/06/21 Javascript
基于Bootstrap使用jQuery实现简单可编辑表格
2016/05/04 Javascript
输入法的回车与消息发送快捷键回车的冲突解决方法
2016/08/09 Javascript
浅谈JavaScript的函数及作用域
2016/12/30 Javascript
JavaScript html5利用FileReader实现上传功能
2020/03/27 Javascript
vue之数据交互实例代码
2017/06/16 Javascript
详谈js的变量提升以及使用方法
2018/10/06 Javascript
webpack4+react多页面架构的实现
2018/10/25 Javascript
Vue.js组件props数据验证实现详解
2019/10/19 Javascript
js重写alert事件(避免alert弹框标题出现网址)
2020/12/04 Javascript
Javascript实现关闭广告效果
2021/01/29 Javascript
快速入门python学习笔记
2017/12/06 Python
Python cookbook(数据结构与算法)从任意长度的可迭代对象中分解元素操作示例
2018/02/13 Python
Python之Numpy的超实用基础详细教程
2019/10/23 Python
python+selenium+chrome批量文件下载并自动创建文件夹实例
2020/04/27 Python
Python发送邮件封装实现过程详解
2020/05/09 Python
Python爬虫实现百度翻译功能过程详解
2020/05/29 Python
django filter过滤器实现显示某个类型指定字段不同值方式
2020/07/16 Python
HTML5添加禁止缩放功能
2017/11/03 HTML / CSS
详解三种方式实现平滑滚动页面到顶部的功能
2019/04/23 HTML / CSS
加拿大票务网站:Ticketmaster加拿大
2017/07/17 全球购物
维多利亚的秘密官方网站:Victoria’s Secret
2018/10/24 全球购物
公司总经理岗位职责范本
2014/08/15 职场文书
党员自我对照检查材料
2014/08/19 职场文书
团员自我评价范文
2015/03/10 职场文书
保护地球的宣传语
2015/07/13 职场文书
2015年评职称个人工作总结
2015/10/15 职场文书