1、什么是函数式编程
- 函数式编程,指的是 函数 数学中的 映射关系,并不是单纯的指函数本身
- 纯函数,指的是 多次 输入和输出 一致的函数
- 有副作用的函数 指的是 依赖外部变量的 函数,因为 内部的 执行结果 就变成了 不可控的
let arr = [1, 2, 3, 4, 5, 6, 7]
// 如下 slice 就是纯函数
arr.slice(0, 3) // [1, 2, 3]
arr.slice(0, 3) // [1, 2, 3]
arr.slice(0, 3) // [1, 2, 3]
arr.slice(0, 3) // [1, 2, 3]
// splice 就不是纯函数
arr.splice(0, 3) // [1, 2, 3]
arr.splice(0, 3) // [4, 5, 6]
arr.splice(0, 3) // [7]
函数式编程中比较 值得记录的点
1、缓存
因为纯函数 是多次输入和输出一致的函数,所以可以使用 对象把结果缓存起来
算法题中 著名 的 斐波那契 数列 就可以使用 缓存来进行 优化回调的问题
function memorize(fn) {
const cache = {}
return function () {
const key = JSON.stringify(arguments)
cache[key] = cache[key] || fn(...arguments)
return cache[key]
}
}
2.柯里化
柯里化 巧妙地利用了 函数 一等公民 以及 闭包 的 特点
function curry (fn) {
const curried = (...args) => (args.length === fn.length) ?
fn(...args) : (..._args) => curried(...args, ..._args)
return curried
}
柯里化 的 具体实现我就不讲了,但是可以说一个 之前就在使用的实际应用场景
在 前端 和 后端 交互的过程中,会出现很多的枚举值,但是大多数人 都是 使用 if else 完事
但是我们可以把枚举值 都提取出来,如下所示
export const saleStatus = {
'停售': 1,
'已售罄': 2,
'待售': 3,
'发售中': 4
}
然后使用一个函数,将这个枚举值 作为 可以 符合 习惯,用 ‘1’ 这样的值读取的新函数
export const commonJudgeType = (enums, default_value = '--') => (status) => {
for (const key in enums) {
if (enums.hasOwnProperty(key)) {
const st = enums[key];
if (typeof st === 'object') {
if (st.code === parseInt(status)) return key
} else {
if (st == status) return key
}
}
}
return default_value
}
export const judgeSale = commonJudgeType(saleStatus, '已售罄')
这里返回了一个新的函数,同时 对传入的 saleStatus 形成了一个闭包。
这样使用 judgeSale 就可以轻易地 将对应的值给读出来了
3、函数组合
在前面的文章中,以及网络上的很多资料里,都有介绍过 redux 中的 compose 函数,
使用这个函数 可以 把 一个函数的颗粒化变小,然后组合成为 一个复杂的函数
function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
// 每个函数的返回值 都会被 当做 一个
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
function reverse(arr) {
return arr.reverse()
}
function join(j) {
return function(arr) {
return return arr.join(j)
}
}
function splite(s) {
return function (str) {
return str.split(s)
}
}
如上面3 个函数
compose(join('-'), reverse, splite(' '))('hello world')
// 输出的结果 就是
// "world-hello"
4. 函子对象
每一个函子 都是一个 盒子,包含了 当前传入的值,不直接操作值。
所有的 操作 由函子完成,map 返回的是 一个包含新之的盒子
所以这个是 支持 链式调用 的
// 函子对象
class Container{
static of (value) {
return new Container(value)
}
// 对函数进行处理
map(fn) {
return Container.of(fn(this._value))
}
constructor(value) {
this._value = value
}
join() {
this._value
}
}
5、正则表达式
这个 完全是抄来的,对于正则表达式 十窍通了九窍
/(\d{4})(\d{2})(\d{2})/.exec('20204040')
/(?<year>\d{4})(?<month>\d{2})(?<day>\d{2})/.exec('20204040')