JavaScript中柯里化函数递归调用:避免重建函数与无点实现
无点风格实现柯里化递归map(无需Y组合子/手动传自身)
嘿,这个问题问到点子上了——递归柯里化函数每次重建确实有点冗余,而且Y组合子的写法又多了一层传参,不够简洁。咱们来试试用闭包+内部递归函数的方式,既能保持柯里化的无点风格,又不用每次递归重建函数,也不需要Y组合子或者手动传自身~
先回顾原问题的痛点
原柯里化map的问题在于每次递归调用map(f)(lst)时,都会重新创建一个新的柯里化函数实例,虽然功能没问题,但确实有不必要的开销:
const map = (f = n => n + 1) => (lst = [1,2,3]) => { if(lst.length === 0) return []; else return [f(...lst.splice(0,1)), ...map(f)(lst)]; }
解决方案:闭包封装内部递归函数
核心思路是把递归逻辑放到柯里化函数的内部,利用闭包捕获传入的f,这样递归时直接调用内部函数,不需要再走外层柯里化的逻辑,也就不会重建函数了:
const map = (f = n => n + 1) => { // 内部递归函数,直接捕获外层的f,复用同一个函数实例 const recursiveMap = (lst = [1,2,3]) => { if (lst.length === 0) return []; // 直接调用recursiveMap,无需重新生成map(f) return [f(lst[0]), ...recursiveMap(lst.slice(1))]; }; return recursiveMap; }; // 用法和原代码完全一致,保持无点风格 const inc = n => n + 1; const map_inc = map(inc); console.log(map_inc([1,2,3])); // => [2,3,4]
更紧凑的箭头函数版本
如果喜欢更简洁的写法,也可以用箭头函数的闭包实现,同样保持无点风格:
const map = (f = n => n + 1) => (recursiveMap = lst => lst.length === 0 ? [] : [f(lst[0]), ...recursiveMap(lst.slice(1))] ); // 调用方式不变 const map_inc = map(n => n + 1); map_inc([1,2,3]); // => [2,3,4]
为什么这个方案可行?
- 无点风格保留:
map(inc)直接返回绑定了inc的处理函数,调用时只需要传数组,和原柯里化用法完全一致 - 无函数重建:
recursiveMap是在第一次调用map(f)时创建的,递归时复用同一个函数实例,不会重复生成新的柯里化函数 - 无需额外依赖:既不用Y组合子,也不需要手动把函数自身作为参数传递,闭包已经帮我们把
f和递归函数绑定好了
内容的提问来源于stack exchange,提问作者SultanLegend
相关产品推荐
相关产品推荐

