大家好,我是蓝胖子的小叮当,今天分享的是JavaScript的第十三章函数柯里化curry,大家在阅读期间有任何的意见或建议都可以留言给我哈!
13.1前言
柯里化是JavaScript中一种函数式编程技巧,指的是将接收多个参数的函数,转化为一系列只接收单一参数的函数的过程。其核心思想是通过分步传递参数,逐步缩小函数的适用范围,最终得到结果,如下的简单示例。
js
// 普通函数:接收3个参数
function sum(a, b, c) {
return a + b + c;
}
sum(1, 2, 3); // 6
// 柯里化函数:每次接收1个参数,返回新函数等待下一个参数
function currySum(a) {
return function(b) {
return function(c) {
return a + b + c;
};
};
}
// 分步调用
currySum(1)(2)(3);
// 6
// 也可分阶段保存中间结果
const add1 = currySum(1);
const add1And2 = add1(2);
add1And2(3);
// 6
13.2核心作用
柯里化核心作用有三个方面:参数复用、延迟执行、函数组合
13.2.1参数复用
js
// 普通函数:计算税费(金额 * 税率)
function calculateTax(amount, rate) {
return amount * rate;
}
// 柯里化后固定税率
function curryTax(rate) {
return function(amount) {
return amount * rate;
};
}
// 复用10%的税率
const calculate10PercentTax = curryTax(0.1);
calculate10PercentTax(100);
// 10(100*0.1)
calculate10PercentTax(200);
// 20(200*0.1)
13.2.2延迟执行
js
mounted() {
let _fn2 = this.curry(this.test)
let _fn3 = _fn2(1)
let _fn4 = _fn3(2)
console.log(_fn4(3))//6
},
methods:{
test(a,b,c){
return a+b+c
},
// 接收一个函数fn作为参数
curry(fn) {
// 返回一个新的函数curried,使用展开运算符...args接收参数
return function curried(...args) {
// 如果传入的参数数量(args.length)大于等于fn的参数数量(fn.length),则直接调用调用fn并返回结果
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
// 不满足原函数参数长度的函数,返回一个新函数 继续等待接收剩余的参数
return function(...args2) {
// 新函数再次调用curried 并将当前参数args和新参数args2拼接后传入
return curried.apply(this, args.concat(args2));
};
}
};
},
}
//计算的参数没有一次性都拿到 可以使用上述形式一步一步获取操作
13.2.3函数组合
js
// 定义柯里化函数
const curry = (fn) =>
(...args) => args.length >= fn.length
? fn(...args)
: (...nextArgs) => curry(fn)(...args, ...nextArgs);
// 定义基础操作(用柯里化处理,使其可复用)
// 筛选年龄大于指定值的用户
const filterByAge = curry((minAge, users) =>
users.filter(user => user.age > minAge)
);
// 筛选指定性别的用户
const filterByGender = curry((gender, users) =>
users.filter(user => user.gender === gender)
);
// 提取用户的指定字段
const pickField = curry((field, users) =>
users.map(user => user[field])
);
// 定义函数组合(从右到左执行)
const compose = (...fns) => (x) =>
fns.reduceRight((result, fn) => fn(result), x);
// 测试数据
const users = [
{ name: '张三', age: 22, gender: '男', score: 85 },
{ name: '李四', age: 17, gender: '女', score: 92 },
{ name: '王五', age: 25, gender: '男', score: 78 },
{ name: '赵六', age: 20, gender: '女', score: 95 },
];
// 使用柯里化+函数组合实现具体功能
// 功能1:筛选成年男性的姓名(年龄>18 + 性别男 → 提取姓名)
const getAdultMaleNames = compose(
pickField('name'), // 最后:提取姓名
filterByGender('男'), // 中间:筛选男性
filterByAge(18) // 首先:筛选成年
);
// 功能2:筛选成年女性的分数(年龄>18 + 性别女 → 提取分数)
const getAdultFemaleScores = compose(
pickField('score'), // 最后:提取分数
filterByGender('女'), // 中间:筛选女性
filterByAge(18) // 首先:筛选成年
);
// 执行并输出结果
console.log('成年男性姓名:', getAdultMaleNames(users));
// 输出:['张三', '王五']
console.log('成年女性分数:', getAdultFemaleScores(users));
// 输出:[95]
13.3局限性
- 不适用于参数数量不固定的函数(如console.log)。
- 过度柯里化可能导致代码可读性下降(嵌套过深)。
- 可能增加内存占用(保存中间状态的函数会暂存)。
13.4总结
柯里化是一种"分而治之"的函数处理技巧,看上去是把简单的事情复杂化,但是却提供了很大的自由度,通过分步传递参数实现参数复用、延迟执行和函数组合。在需要灵活控制参数传递的场景(如工具函数、函数式编程)中非常实用,但需避免过度使用,平衡代码简洁性与可读性。
好啦,关于函数柯里化的知识点就总结到这里,如果有什么疑问、意见或建议,都可畅所欲言,谢谢大家,我也将持续更新。
预告:后续会根据情况出一些前端框架方面的内容,js的内容也会继续补充。