使用Lodash的curryRight实现断言数组过滤器出错,是否理解有误?
你确实对curryRight的用法存在误解,核心问题出在Lodashfilter函数的参数结构以及curryRight处理参数的逻辑上,我来一步步拆解清楚:
为什么你的原代码不工作?
首先看Lodash_.filter的函数签名:
_.filter(collection, predicate, [thisArg])
它的func.length是3(因为声明了3个参数,哪怕第三个是可选的)。而_.curryRight的作用是从右往左依次绑定函数的参数,对于参数长度为3的函数,它的绑定顺序是:
- 最右边的
thisArg - 中间的
predicate - 最左边的
collection
你写的const curriedFilter = curryRight(filter),当你把断言函数传给curriedFilter时,这个函数被当作thisArg传给了_.filter,而真正需要的predicate参数依然是undefined。此时_.filter因为没有有效过滤条件,会直接返回原数组,这就是为什么你得到了和输入一样的结果。
修正方案
这里有几种可行的解决方式,选哪种都可以:
方案1:给curryRight显式指定参数数量
我们可以告诉curryRight只处理前2个参数(忽略可选的thisArg),这样它就会按照我们预期的顺序绑定predicate和collection:
const { curryRight, filter, flowRight } = require('lodash'); const curriedFilter = curryRight(filter, 2); // 明确只处理2个参数 const filterFromPredicates = (predicateList) => flowRight(...predicateList.map(curriedFilter)); // 测试验证 const myFilter = filterFromPredicates([(x) => x > 2, (x) => x > 4]); console.log(myFilter([1,2,3,4,5,6,7,8,9])); // 输出 [5,6,7,8,9]
方案2:用flip调换参数顺序后再curry
如果觉得curryRight容易搞混,可以先用_.flip把filter的参数顺序换成(predicate, collection),再用普通的curry:
const { curry, filter, flowRight, flip } = require('lodash'); const curriedFilter = curry(flip(filter)); // 先接收断言,再接收数组 const filterFromPredicates = (predicateList) => flowRight(...predicateList.map(curriedFilter));
方案3:保留你手动实现的curriedFilter
你自己写的:
const curriedFilter = (predicate) => (array) => array.filter(predicate);
其实是最直观且不容易出错的方式,它明确指定了参数顺序,完全避开了Lodashfilter可选参数带来的curry绑定问题,要是觉得够用,直接用这个版本也很好。
补充说明
你用flowRight组合多个过滤器是对的,它会从右往左执行过滤(先执行x>4的过滤,再对结果执行x>2的过滤),最终得到两个条件都满足的元素,和你预期的一致。
内容的提问来源于stack exchange,提问作者jorgen

