JavaScript ES6 函数式编程指南入门
1.简介
1.1 什么是函数式编程?
f(x) = y
不就是尽量以函数的形式的形式写代码吗?
是的!
但是函数的形式要遵守一定的规则,然后可以达到很好的效果,
但是其中要有几点是要必须遵守的。
- 函数总是接收 一个 参数
- 函数总是返回 一个 值
- 对于相同的输入都将返回相同的值
- 函数逻辑不依赖其他全局变量
至于这样写的好处,暂时还未品尝到。暂时还是先把概念搞清楚。 (后续更新)
- 缓存
1.2 引用透明性
相同的输入都将返回相同的值,这个特性又被叫做引用透明性。
下面的这个过程被称为:替换模型(Substitution Model)
const identity = i => i;
1 + identity(1)
// 等同于
1 + 1
这个好处就是可以用作缓存。 假设有一个函数式算 一个数的阶乘。 输入: 5 输出:120, 加入再次输入5, 根据特性,就知道结果依然是 120(并且只依赖一个输入:5),. 有了这个特性之后,就可以用一个变量来缓存 输入: 5 的结果。 再次输入5:直接将缓存结果返回,无需重复计算
1.3 声明式、命令式、抽象
函数式编程主张声明式编程和编写抽象代码
- 命令式:告诉编译器“如何做”
- 声明式:告诉编译器“做什么”
// 告诉编译器 做什么,获得数组长度,循环数组,等等。。。
const array = [1,2,3]
for(i = 0; i < array.length; i++){
console.log(i)
}
const array = [1,2,3]
// 这里只做了一个 “如何做”的抽象函数
array.forEach(item => { console.log(item )})
1.4 纯函数
纯函数的定义是,对于相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用,也不依赖外部环境的状态。
1.5 管道与组合
虽然一个函数都只解决一个问题,但是可以使用管道或组合来完成复杂任务。
2.高阶函数(HOC High-Order Function
2.1 理解概念
概念:接收一个函数作为参数并且/或者返回函数作为输出的函数,称为高阶函数。
个人理解:使用函数来代替数据传递
const tellType = (arg) => {
// 已知tellType 可以判断类型
if(typeof arg === 'function') {
arg()
} else {
console.log('The passed data is' + arg)
}
}
const dataFn = () => {
console.log('I am data function')
}
tellType(dataFn)
这就是一个例子,把函数dataFn, dataFn 也可以理解为数据。 传递给了 tellType, 数据通过函数传递。
2.2 返回一个函数
const crazy = () => String;
const fn = crazy()
console.log(fn('hoc'))
重点: crazy 执行并返回了一个指向 String 的函数引用,注意:只返回了一个函数引用,并没有执行函数
2.3 抽象与高阶函数
高阶函数就是定义抽象。
什么是抽象?与函数式编程有什么关系?
抽象的作用:一辆车,只要加油就能启动,不用去关心具体零部件之间怎样发生作用的。 抽象的目的:达到目标,而不必关心底层的系统概念。
2.4 通过高阶函数实现抽象
如何实现抽象呢?
自己理解:只要目的是达到目标,而不必关心底层具体实现的代码,就可以叫做抽象代码。
上面做了一个 forEach 的抽象函数,这个函数式遍历了数组,那么怎么做一个 遍历对象的 抽象函数呢?
1.遍历给定对象上的所有 key, 2.判断 key 是否属于对象本身 3.如果 步骤2 值为true, 获取 key的值(value)
const obj = {
name: '111',
age: 999,
sex: 'man'
}
const forEachObj = (obj, fn) => {
for (const key in obj) {
if (Object.hasOwnProperty.call(obj, key)) {
const value = obj[key];
fn(key, value)
}
}
}
forEachObj(obj, (key, value) => {
console.log(key, value)
})
forEach 和 forEachObj 都是高阶函数,他们都使开发者专注于任务(通过传递对应的函数),而抽象出遍历的部分
是否有了更深的理解?