js 函数 柯里化 的学习
函数柯里化是什么?
接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
分析一下
- 输入是一个函数,并且这个函数拥有n个参数
- 输出也是一个函数,并且可以使用fn()()()这种方式调用
- 参数被柯里化过程中的函数被拆分
通过分析可以得到 (1)需要对函数的参数进行收集(闭包缓存)(2)链式调用
那我们用柯里化来简单实现一个需求
add(2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)() // 133
//简单实现需求
function add(){
let ags= [...arguments]
let curry= function (){
if(arguments.length===0){
return ags.reduce((a,b)=>a+b)
}else{
ags= [..ags,...arguments]
return curry
}
}
//形成闭包
return curry
}
上面虽然实现了主要功能,但是代码的质量不是很高!无法进行拓展
我们需要把上面的代码进行单一职责划分(1)参数收集(2)逻辑部分(相加)
function curry () {
let ags = [...arguments]
let currying = function () {
if (arguments.length === 0) {
return ags
} else {
ags = [...ags, ...arguments]
return currying
}
}
//形成闭包
return currying
}
function add (data) {
return data.reduce((a, b) => a + b)
}
add(curry(2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)()) //133
或者
function curry (fn,...data) {
//参数传递的时候 缓存除了第一个参数的函数之外的所有参数
let ags = [...data]
// let args = [].slice.call(arguments, 1);
//[].slice.call(arguments, 1)等同于arguments.slice(1)
//[].slice.call 的原因是 arguments是个类数组 并不具备array原型上的方法
//直接使用 arguments.slice(1)无法使用
let currying = function () {
if (arguments.length === 0) {
return fn.apply(this,ags)
} else {
ags = [...ags, ...arguments]
return currying
}
}
//形成闭包
return currying
}
function add () {
return [].reduce.call(arguments,(a, b) => a + b)
}
curry(add,2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)() //133
整体看上去还是不够简洁 接着简化
function curry(fn,data=[]){
return ( ...args )=>{ //args 为curry的 第二个参数 是每一项的数据
//自执行函数 前面函数会接收后面传递的参数
//a为拼接的累加数据 b为 ...args 每一次调用的形参数据
//链式调用当前形参的长度为0时 结束递归循环 并返回调用函数把所有收集的参数传递给执行参数
return ((a,b)=> b.length === 0?fn(...ages): curry(fn,a))([...data,...args],...args)
}
}
let adds = curry((...x) => x.reduce((a, b) => a + b))
console.log(adds(2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)()) //133
////遇到参数个数为0的情况才执行
console.log(adds(2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)) //函数
上面看出来 柯里化的作用之一是收集数据 参数复用;利用闭包的特性,将所有参数都搜集到之后再一并执行。
function curry(fn, ...args) {
return function(...innerArgs) {
const allArgs = [...args, ...innerArgs];
if (fn.length <= allArgs.length) {
// 说明已经接受完所有参数,这个时候可以执行了
return fn.apply(this, allArgs);
} else {
// 继续返回函数,收集参数
return curry(fn, ...allArgs);
}
}
}
function curry(fn, ...args) {
return function(...innerArgs) {
const allArgs = [...args, ...innerArgs];
if (fn.length <= allArgs.length) {
// 说明已经接受完所有参数,这个时候可以执行了
return fn.apply(this, allArgs);
} else {
// 继续返回函数,收集参数
return curry(fn, ...allArgs);
}
}
}
const amount = [
{ deposit: 120, finalPayment: 200 },
{ deposit: 110, finalPayment: 300 },
{ deposit: 130, finalPayment: 100 },
];
const sort = curry(function(field, a, b) {
return a[field] - b[field];
})
console.log(amount.slice().sort(sort('deposit'))); // deposit进行排序
console.log(amount.slice().sort(sort('finalPayment'))); // finalPayment进行排序