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!
JavaScript中的工厂函数的更多相关文章
- JavaScript中的工厂方法、构造函数与class
JavaScript中的工厂方法.构造函数与class 本文转载自:众成翻译 译者:谢于中 链接:http://www.zcfy.cc/article/1129 原文:https://medium.c ...
- 借助JavaScript中的时间函数改变Html中Table边框的颜色
借助JavaScript中的时间函数改变Html中Table边框的颜色 <html> <head> <meta http-equiv="Content-Type ...
- 前端学习 第二弹: JavaScript中的一些函数与对象(1)
前端学习 第二弹: JavaScript中的一些函数与对象(1) 1.apply与call函数 每个函数都包含两个非继承而来的方法:apply()和call(). 他们的用途相同,都是在特定的作用域中 ...
- 理解和使用 JavaScript 中的回调函数
理解和使用 JavaScript 中的回调函数 标签: 回调函数指针js 2014-11-25 01:20 11506人阅读 评论(4) 收藏 举报 分类: JavaScript(4) 目录( ...
- JavaScript中变量和函数声明的提升
现象: 1.在JavaScript中变量和函数的声明会提升到最顶部执行. 2.函数的提升高于变量的提升. 3.函数内部如果用var声明了相同名称的外部变量,函数将不再向上寻找. 4.匿名函数不会提升. ...
- javascript中使用md5函数
javascript中使用md5函数 这对于js来讲本来是没有的,现在可以自己定义一个md5的函数,达到加密效果. var hexcase = 0; function hex_md5(a) { if ...
- 在 JavaScript 中使用构造器函数模拟类
今天,我们要讲的是在 JavaScript 中使用构造器函数(construcor function)模拟类. 构造器函数简介 你可以使用 ES6 的 class 关键字来实现类,不过我建议你使用传统 ...
- 来一轮带注释的demo,彻底搞懂javascript中的replace函数
javascript这门语言一直就像一位带着面纱的美女,总是看不清,摸不透,一直专注服务器端,也从来没有特别重视过,直到最近几年,javascript越来越重要,越来越通用.最近和前端走的比较近,借此 ...
- 理解javascript中的回调函数(callback)【转】
在JavaScrip中,function是内置的类对象,也就是说它是一种类型的对象,可以和其它String.Array.Number.Object类的对象一样用于内置对象的管理.因为function实 ...
随机推荐
- Python配置工具类ConfigParser使用
ConfigParser模块定义了类ConfigParser,用于实现配置文件解释器.该模块ConfigParser在Python3中,已更名为configparser. 一,函数介绍 1.读取配置文 ...
- python基础之Day4
流程判断 一.if 1.语法一 各条件都执行 if条件1: if条件2: if条件3: 2.语法二 if多分支,自上而下执行,一旦满足条件,后面代码即使满足条件也不会执行 if条件1: elif条件2 ...
- Docker虚拟化实战学习——基础篇(转)
Docker虚拟化实战学习——基础篇 2018年05月26日 02:17:24 北纬34度停留 阅读数:773更多 个人分类: Docker Docker虚拟化实战和企业案例演练 深入剖析虚拟化技 ...
- div同时使用两个class
<p class="con hide">...</p> 1:使用空格分割 2:这个段落将同时应用这两个 class 制定的规则 3:如果二者有重叠,后者覆盖 ...
- MySQL5.7的安装(CentOS 7 & Ubuntu 16.04)
CentOS 通过 yum 安装MySQL5.7 Yum Repository 下载地址:https://dev.mysql.com/downloads/repo/yum/ 选择相应的版本进行下载:R ...
- 【UI测试】--快捷键组合
- DataTable xml 互相转换
//测试方法 public static DataTable Test() { string savePath = System.AppDomain.CurrentDomain.BaseDirecto ...
- [C#.Net]C#连接Oracle数据库的方法
首先介绍下开发环境:WIn10 64bit+Visual Studio 2015+Oracle10ClientWin32(只是客户端,如果安装整个数据库也是可以的) 目前了解C#中连接Oracle数据 ...
- SpringMVC 学习 十 SSM环境搭建(三)springMVC文件配置
SpringMVC文件配置的详细过程,可以查看springMVC环境搭建的注解配置篇<springMVC学习三 注解开发环境搭建> <?xml version="1.0&q ...
- mysql之表与表关联和表操作
一 表于表之间的关联 foregin key:设置外键表于表之间建立关联. 多对一关联: 创建步骤,应该先创建好被关联的那一张表,然后再去创建关联的那一张表. 关联表的多条对应着被关联的那张表的一条记 ...