js函数柯里化

柯里化是把接受多个参数 的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新技术。

用数学表达式来理解可能更直观:

假设有一个函数 f,它接受三个参数:

f(x, y, z) =result

柯里化之后,它变成了这样一系列的嵌套函数:

f(x)+f(y)+f(z)=result

也就是:

fn(x, y, z) 变成 fn(x)(y)(z)

核心思想 :通过闭包缓存参数,直到集齐所有参数才执行最终逻辑。

简单代码示例:

javascript 复制代码
function add(x, y,z) {
    return x + y + z;
}

console.log(add(1, 2, 3)); // 输出: 6

柯里化写法

javascript 复制代码
function curriedAdd(x) {
    return function(y) {
        return function(z) { 
            return x + y + z
       };
    }
}

// 或者使用 ES6 箭头函数简化:
const curriedAddArrow = x => y => z=>x + y + z;

console.log(curriedAdd(1)(2)(3)); // 输出: 6

发生了什么?

  1. curriedAdd(1) 执行后,返回了一个记住了 x=1 的新函数。

  2. 紧接着调用这个新函数并传入 2,返回了一个记住了 y=2 的新函数。

  3. 紧接着调用这个新函数并传入 3,返回了一个记住了 z=3 的新函数。

  4. 内部函数访问闭包中的 x 和传入的 y还有z,计算 1 + 2 + 3。

通用柯里化函数的实现 (核心技能)

javascript 复制代码
function curry(fn) {
    // limit 是 fn 声明时定义的参数个数 (arity)
    const limit = fn.length;

    return function curried(...args) {
        // 1. 如果当前收集的参数 args 数量 >= limit,说明参数够了,执行原函数
        if (args.length >= limit) {
            return fn.apply(this, args); //this是window,最后的结果是window.fn
        } else {
            // 2. 如果参数不够,返回一个新函数来继续接收剩余参数 (...moreArgs)
            return function(...moreArgs) {
                // 将之前的 args 和新的 moreArgs 合并,递归调用 curried
                return curried.apply(this, args.concat(moreArgs));
            }
        }
    };
}

测试这个工具

javascript 复制代码
// 一个接受4个参数的普通函数
function sum(a, b, c, d) {
    return a + b + c + d;
}

// 将其柯里化
const curriedSum = curry(sum);

// 方式 1: 一次性传完 (依然支持)
console.log(curriedSum(1, 2, 3, 4)); // 10

// 方式 2: 分步传参 (标准柯里化)
console.log(curriedSum(1)(2)(3)(4)); // 10

// 方式 3: 混合传参 (非常灵活)
console.log(curriedSum(1, 2)(3)(4)); // 10

使用方向与实战场景 (Use Cases)

你可能会问:"直接传参不好吗?为什么要搞这么麻烦?" 柯里化的主要优势在于:参数复用 、延迟执行 和代码组合。

场景一:参数复用(创建偏函数)

假设我们需要验证很多个字符串是否符合某种正则表达式(例如验证是否是邮箱,或是否是数字)。

不使用柯里化:

javascript 复制代码
function check(reg, txt) {
    return reg.test(txt);
}

// 每次都要传正则
check(/\d+/g, 'test');       // false
check(/[a-z]+/g, 'test');    // true
check(/\d+/g, '123');        // true

使用柯里化: 我们可以固定住"正则"这个参数,生成具体的检测函数。

javascript 复制代码
const curriedCheck = curry(check); // 使用上面定义的 curry 工具

// 创建专门验证数字的函数 (复用了 /\d+/g 参数)
const hasNumber = curriedCheck(/\d+/g);

// 创建专门验证字母的函数
const hasLetter = curriedCheck(/[a-z]+/g);

// 现在使用起来非常语义化,且不用重复写正则
console.log(hasNumber('test')); // false
console.log(hasNumber('123'));  // true
console.log(hasLetter('test')); // true

与 map 等高阶函数配合

在处理数组时,柯里化能让代码极其简洁。

假设我们要获取数组中所有对象的 id 属性。

javascript 复制代码
const persons = [{ id: 1, name: 'A' }, { id: 2, name: 'B' }];

// 普通写法
const ids1 = persons.map(p => p.id);

// 柯里化写法
const getProp = curry((key, obj) => obj[key]);
const getId = getProp('id'); // 预设我们要取 'id'

// 代码极具可读性:map (获取id)
const ids2 = persons.map(getId); 

console.log(ids2); // [1, 2]

. 总结 (Summary)

优点

  • 复用性 :通过固定部分参数,生成功能更具体的小函数(如 hasNumber, getId)。

  • 可读性:代码语义更加清晰,接近自然语言。

  • 延迟执行:直到所有参数凑齐前,函数都不会真正运行,可以分阶段积累数据。

  • 函数式编程基石 :柯里化让函数变成了"单参数"函数,这使得函数组合(Composition)变得容易得多(类似流水线 f(g(x)))。

相关推荐
deli0071 分钟前
Skill 怎么写才被 Agent 命中?18 条规则做成 SKILL.md 校验器,规范样例 92 分
前端
Hum8le2 分钟前
CTF题目《easy_web》(安洵杯 2019 变种 Web)
前端·安全·web安全
coding漫漫长路2 分钟前
二值化后还剩1212个黑点,OCR却认成了乱码
前端
不可能片场3 分钟前
AI视频口型对齐 用音频驱动说话镜头
前端·electron
Lank_M4 分钟前
OCR一个字没认错,倾斜2.5°却把行序排乱了
前端
weixin199701080164 分钟前
《1688消息服务落地方案:alibaba.message.* 与 Webhook 回调的可靠性与重试策略》(附Python源码)
开发语言·python
daols887 分钟前
vue 表格组件 vxe-table 实现自定义多行编辑功能
前端·javascript·vue.js·vxe-table
不要试图纠正别人11 分钟前
别让大模型算钱:我把优惠券组合优化写成了确定性算法
前端
志尊宝12 分钟前
Vue3 零基础每日笔记(075):图片懒加载与骨架屏
javascript·vue.js·笔记
ZHOUPUYU14 分钟前
PHP 9.0 前瞻:下一代 PHP 会带来哪些新功能?
android·开发语言·php