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 相关文章推荐
用jquery与css打造个性化的单选框和复选框
Oct 20 Javascript
使用jQuery实现的网页版的个人简历(可换肤)
Apr 19 Javascript
javascript封装 Cookie 应用接口
Aug 07 Javascript
JS模拟酷狗音乐播放器收缩折叠关闭效果代码
Oct 29 Javascript
jsonp跨域请求数据实现手机号码查询实例分析
Dec 12 Javascript
解析Javascript单例模式概念与实例
Dec 05 Javascript
全面解析vue中的数据双向绑定
May 10 Javascript
详解node如何让一个端口同时支持https与http
Jul 04 Javascript
angularJs 表格添加删除修改查询方法
Feb 27 Javascript
详解如何使用koa实现socket.io官网的例子
Nov 04 Javascript
AngularJS上传文件的示例代码
Nov 10 Javascript
vue实现表单未编辑或未保存离开弹窗提示功能
Apr 08 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执行速度全攻略(下)
2006/10/09 PHP
mysql5写入和读出乱码解决
2006/11/25 PHP
php图片验证码代码
2008/03/27 PHP
用PHP进行MySQL删除记录操作代码
2008/06/07 PHP
Discuz!X中SESSION机制实例详解
2015/09/23 PHP
WordPress中转义HTML与过滤链接的相关PHP函数使用解析
2015/12/22 PHP
CodeIgniter配置之SESSION用法实例分析
2016/01/19 PHP
smarty自定义函数用法示例
2016/05/20 PHP
利用php操作memcache缓存的基础方法示例
2017/08/02 PHP
PHP中number_format()函数的用法讲解
2019/04/08 PHP
使用jQuery中的when实现多个AJAX请求对应单个回调的例子分享
2014/04/23 Javascript
js操作table元素实现表格行列新增、删除技巧总结
2015/11/18 Javascript
jquery密码强度校验
2015/12/02 Javascript
详解Javascript继承的实现
2016/03/25 Javascript
JS实现pasteHTML兼容ie,firefox,chrome的方法
2016/06/22 Javascript
jQuery EasyUI tree 使用拖拽时遇到的错误小结
2016/10/10 Javascript
js 中获取制定的cook信息实现方法
2016/11/19 Javascript
js实现以最简单的方式将数组元素添加到对象中的方法
2017/12/20 Javascript
一些手写JavaScript常用的函数汇总
2019/04/16 Javascript
python进阶教程之词典、字典、dict
2014/08/29 Python
python 开发的三种运行模式详细介绍
2017/01/18 Python
详解python3中socket套接字的编码问题解决
2017/07/01 Python
python3 pandas 读取MySQL数据和插入的实例
2018/04/20 Python
python采集微信公众号文章
2018/12/20 Python
python gensim使用word2vec词向量处理中文语料的方法
2019/07/05 Python
python用tkinter实现一个gui的翻译工具
2020/10/26 Python
Shopee印度尼西亚:东南亚与台湾市场最大电商平台
2018/06/17 全球购物
4s客服专员岗位职责
2013/12/01 职场文书
读书活动实施方案
2014/03/10 职场文书
施工安全责任书
2014/04/14 职场文书
《周恩来的四个昼夜》观后思想汇报范文两篇
2014/09/10 职场文书
明星邀请函
2015/02/02 职场文书
统计工作个人总结
2015/03/03 职场文书
青春雷锋观后感
2015/06/10 职场文书
班级班风口号大全
2015/12/25 职场文书
MySQL图形化管理工具Navicat安装步骤
2021/12/04 MySQL