函数式编程
含义:函数式编程是一种强调以函数使用为主的开发风格,也是一种规范。
什么是柯里化(Currying)
把接受多个参数的函数转化成接收一个单一参数的函数,并返回接受剩余参数并且返回结果的函数。柯里化函数能持续地返回一个新函数直至所有参数用尽为止,这些参数会通过闭包被缓存下来,当柯里化链执行到最后一个函数时会被全部执行。
纯函数
纯函数是对给定的输入返还相同输出的函数。返回结果不会被外部干预。
// 错误示例
let x = 3;
let sum = (y)=>x+y;
console.log(sum(7)) // 10 这里的计算结果不可预测,计算结果受到了外部干扰。
// 正确示例
let sum = x=>x+3;
console.log(sum(7))
可以组装成复杂任务的可能性。符合模块化概念及单一职责原则。
柯里化
基础
我们对于下面sum函数非常熟悉
function sum(x,y){
return x+y
}
console.log(sum(1,2)) // 3
我们对上函数进行柯里化
function sum(x,y){
return x+y
}
function curry(fn){
return function (x){
return function (y){
return fn(x,y)
}
}
}
let mySum = curry(sum)
console.log(mySum(2)(5)) // 7
上面验证了柯里化就是把一个多参数函数转化成一个嵌套的一元函数的过程。
多参数(通过递归实现curry函数)
function sum(x,y,z){
return x+y+z
}
function curry (fn){
const c = (...args)=>(args.length === fn.length)? //fn.length 为参数个数
fn(...args):(..._args)=>c(...args,..._args)
return c
}
let mySum = curry(sum)
console.log(mySum(2)(5)(3)) // 10
console.log(mySum(2,5)(3)) // 10
该方法几乎为最简洁、代码行数最少的实现方法了。
首先我们能确定,实现柯里化的核心就是要确定传入参数的个数,并通通取到。
其次,我们得知道,fn.length为fn函数接受的参数个数,那么该实现方法就能解读为:
不断递归获取传入参数,直到取到的参数个数等于fn的参数个数为止,最终将获取到的所有参数传给fn并返回执行结果。
参数复用
// 实现一个判断数据类型的方法
const checktype = function(type, value) {
return Object.prototype.toString.call(value) === `[object ${type}]`;
}
checktype('Number',2); // true
checktype('Number',12); // true
checktype('Number',51); // true
// 这种方式每次都需要将type 'Number'参数传递过去
function curry(fn,type){
return function (value){
return fn(type, value)
}
}
// 检查Number类型
let isNumber = curry(checktype,'Number')
console.log(isNumber(2)) //true
// 检查String类型
let isString = curry(checktype,'String')
console.log(isString('hello')) //true
这里就是实现了参数的复用,这样的实现为后续的扩展调用带来了很大的方便。
到这里我们应该能感觉到了柯里化函数的强大,通过和纯函数的配合使用他可以优雅的实现复杂功能。
组合(composition)
需求:获取一个字符串中所有句号数的奇偶
- 获取所有句号
- 统计长度
- 判断奇偶
let str = "大家好,我是小强。我今年12岁,来自5班。我喜欢看plmm。"
// 1.获取句号
let sentenceNum = str=>str.match(/。/g)
// 2.统计长度
let getCount = arr=>arr.length
// 3.判断奇偶
let oddOrEven = num=>num%2===0?'偶数':'奇数'
// 组合:找到句号统计长度最后判断奇偶数
let compose = (...fns) =>str=>fns.reduce((result,fn)=>fn(result),str)
const myfn = compose(sentenceNum,getCount,oddOrEven);
console.log(myfn(str)); // 奇数
管道(pipe)
compose 执行是从右到左,pipe是从左至右的执行。
const pipe = (...fns)=>val=>fns.reduce((acc,fn)=>fn(acc),val);
管道、组合 取舍 :管道及组合最大区别在于执行顺序的不同,数据流向不同,达到目的是类似的,所以无优 劣之分。
组合及管道的意义 把很多小函数组合起来完成更复杂的逻辑。
参考