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进行排序
分类:
javasrcipt
, 设计模式
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· 单线程的Redis速度为什么快?
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码