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 相关文章推荐
js获取url参数值的两种方式
Sep 10 Javascript
js获取下拉列表的值和元素个数示例
May 07 Javascript
javascript实现分栏显示小技巧附图
Oct 13 Javascript
js实现九宫格图片半透明渐显特效的方法
Feb 16 Javascript
JavaScript实现函数返回多个值的方法
Jun 09 Javascript
C#中使用迭代器处理等待任务
Jul 13 Javascript
CSS3 3D 技术手把手教你玩转
Sep 02 Javascript
layui table设置前台过滤转义等方法
Aug 17 Javascript
详解小程序用户登录状态检查与更新实例
May 15 Javascript
vue自定义switch开关组件,实现样式可自行更改
Nov 01 Javascript
jquery选择器和属性对象的操作实例分析
Jan 10 jQuery
iview实现图片上传功能
Jun 29 Javascript
老生常谈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实现json编码的方法
2015/07/30 PHP
浅谈PHP面向对象之访问者模式+组合模式
2017/05/22 PHP
异步加载script的代码
2011/01/12 Javascript
jQuery实现彩带延伸效果的网页加载条loading动画
2015/10/29 Javascript
基于jQuery实现Ajax验证用户名是否存在实例
2016/03/30 Javascript
javascript使用 concat 方法对数组进行合并的方法
2016/09/08 Javascript
微信小程序(应用号)开发新闻客户端实例
2016/10/24 Javascript
详解Angular.js指令中scope类型的几种特殊情况
2017/02/21 Javascript
Bootstrap栅格系统使用方法及页面调整变形的解决方法
2017/03/10 Javascript
js实现京东秒杀倒计时功能
2019/01/21 Javascript
JS中的防抖与节流及作用详解
2019/04/01 Javascript
微信小程序错误this.setData报错及解决过程
2019/09/18 Javascript
vue实现短信验证码登录功能(流程详解)
2019/12/10 Javascript
详解微信小程序(Taro)手动埋点和自动埋点的实现
2021/03/02 Javascript
Python使用urllib2模块实现断点续传下载的方法
2015/06/17 Python
python3实现TCP协议的简单服务器和客户端案例(分享)
2017/06/14 Python
利用numpy实现一、二维数组的拼接简单代码示例
2017/12/15 Python
Python设计模式之工厂模式简单示例
2018/01/09 Python
利用python实现简易版的贪吃蛇游戏(面向python小白)
2018/12/30 Python
Python 实现数据结构中的的栈队列
2019/05/16 Python
python高斯分布概率密度函数的使用详解
2019/07/10 Python
完美解决pycharm导入自己写的py文件爆红问题
2020/02/12 Python
pytorch实现MNIST手写体识别
2020/02/14 Python
HTML5中使用json对象的实例代码
2018/09/10 HTML / CSS
英国Zoro工具:手动工具,电动工具和个人防护用品
2016/11/02 全球购物
环法自行车赛官方商店:Le Tour de France
2017/08/27 全球购物
台湾7-ELEVEN线上购物中心:7-11
2021/01/21 全球购物
平面设计师的工作职责
2013/11/21 职场文书
工程管理专业毕业生自荐信
2014/01/24 职场文书
绩效考核实施方案
2014/03/18 职场文书
2015年机关党委工作总结
2015/05/23 职场文书
小学生家长意见
2015/06/03 职场文书
小学生暑假安全保证书
2015/07/13 职场文书
2016中秋节月饼促销广告语
2016/01/28 职场文书
Golang 编译成DLL文件的操作
2021/05/06 Golang
python scipy 稀疏矩阵的使用说明
2021/05/26 Python