Lodash中filter函数参数顺序疑问:数组为何先于函数传入?
filter参数顺序是数组在前、函数在后? 这个问题我当初刚接触Lodash时也困惑过——毕竟像原生JavaScript的Array.prototype.filter、Python的filter()、Ramda.js的filter都是把判断函数放在前面,唯独Lodash反着来。后来查了不少资料和社区讨论,大概理清了背后的设计逻辑,也找到了一些类似的案例:
一、Lodash这么设计的核心原因
1. 优先适配柯里化与函数复用
Lodash的很多API设计都围绕函数式编程中的柯里化展开。把数组作为第一个参数的话,你可以很方便地生成一个“绑定了特定数据源”的过滤函数,后续重复使用:
// 先绑定数据源,生成可复用的过滤函数 const filterActiveUsers = _.filter(userList); // 后续多次调用,只需要传入判断逻辑 const activeAdmins = filterActiveUsers(u => u.role === 'admin' && u.isActive); const activeEditors = filterActiveUsers(u => u.role === 'editor' && u.isActive);
这种方式在需要对同一数据集执行多种过滤逻辑的场景下,代码会更简洁、复用性更强。如果参数顺序反过来,柯里化后生成的是“绑定了判断逻辑”的函数,虽然也有用,但Lodash团队更倾向于优先支持“数据源固定,操作多变”的场景。
2. 保持全库API风格的一致性
Lodash里几乎所有集合操作类函数(比如_.map、_.reduce、_.forEach、_.find)都是遵循“数据在前,操作函数/配置在后”的规则。这样设计的好处是,用户只要记住一个函数的参数顺序,就能举一反三,降低整个库的学习成本。
对比原生JS的数组方法(比如arr.filter(fn)),那是因为原生方法是挂载在数组原型上的,数组本身是调用上下文,所以参数只需要传函数;但Lodash是独立的工具函数库,所有操作都是以“数据作为输入”的形式传递,统一参数顺序能让API更规整。
3. 延续Underscore.js的设计传统
Lodash最初是作为Underscore.js的增强版诞生的,而Underscore的_.filter就是数组在前、函数在后的参数顺序。为了让原Underscore用户能平滑迁移到Lodash,Lodash团队延续了这个设计,保证了向下兼容性。
二、还有哪些语言/库采用类似的参数顺序?
其实不少工具库或语言的内置函数都采用“数据在前,操作在后”的设计,举几个常见的例子:
- Underscore.js:作为Lodash的前辈,它的所有集合操作函数(
_.each、_.map等)参数顺序和Lodash完全一致。 - PHP的
array_filter:PHP内置的数组过滤函数,语法是array_filter($array, $callback),数据在前,回调函数在后。 - C# LINQ的静态方法:比如
Enumerable.Where(source, predicate),其中source是数据源,predicate是判断函数,参数顺序和Lodash一致(不过C#更常用扩展方法source.Where(predicate))。 - jQuery的
$.each:jQuery的通用遍历函数,语法是$.each(collection, callback),也是数据在前,回调在后。
内容的提问来源于stack exchange,提问作者isar

