☰
jstips 精读:柯里化(Currying)与部分应用(Partial Application)的区别与实现
2026/10/9 1:50:44 网站建设 项目流程
  • 教程

【免费下载链接】jstips

This is about useful JS tips!

项目地址:https://gitcode.com/gh_mirrors/js/jstips
点击查看免费下载

柯里化(Currying)与部分应用(Partial Application)都是将函数转换为「参数个数更少」的另一函数的两种经典函数式编程手法。本文以 jstips 第 28 期 柯里化和部分應用程式 为核心骨架,结合仓库中的中英文对应版本,讲透二者的数学定义、JavaScript 实现、核心区别与实用场景,读完即可写出自己的curry与partApply工具函数,并正确判断何时该用哪一种。

一、为什么要区分柯里化与部分应用

在函数式编程中,我们经常希望把一个「一次接收多个参数」的函数,改造成「能分步接收参数」的形式,从而复用中间结果、组合小函数或延迟执行。jstips第 28 期用最简洁的方式点明了二者的定位:

Currying and partial application are two ways of transforming a function into another function with a generally smaller arity.

即:柯里化和部分应用都是把一个函数转换成另一个「通常参数个数(arity)更小」的函数的方法。但二者转换的规则完全不同——柯里化改变的是函数的调用形态,而部分应用改变的是函数的参数数量。下面分别展开。

二、柯里化(Currying):把二元函数拆成一串一元函数

2.1 数学定义

柯里化是将一个函数

f: X * Y -> R

转换成

f': X -> (Y -> R)

与「用两个参数调用f」不同,我们先用第一个参数调用f',得到的结果是一个函数,再用第二个参数调用这个函数,最终得到结果。

因此,未柯里化的f是这样调用的:

f(3, 5)

而柯里化后的f'是这样调用的:

f(3)(5)

2.2 代码对比:未柯里化 vs 柯里化

未柯里化的加法函数:

function add(x, y) { return x + y; } add(3, 5); // returns 8

柯里化后的加法函数:

function addC(x) { return function (y) { return x + y; } } addC(3)(5); // returns 8

注意两者的关键差异:addC(3)并不立即求和,而是返回一个「记住了x = 3的闭包函数」,该闭包等待第二个参数y传入后才计算x + y。这正是闭包(closure)在函数式编程中的典型应用——内层函数通过作用域链捕获外层参数x。

2.3 柯里化的规则与通用实现

柯里化将一个二元函数转变为一个一元函数,这个一元函数又返回另一个一元函数:

curry: (X × Y → R) → (X → (Y → R))

通用的柯里化实现(来自 第 28 期文档):

function curry(f) { return function(x) { return function(y) { return f(x, y); } } }

调用方式:curry(add)(3)(5)返回8。curry接受一个二元函数f,先固定住第一个参数x,返回一个等待y的新函数,最终在两层闭包都就位后才调用原始函数f(x, y)。

2.4 向多元函数的自然延伸

仓库中的另一期姊妹篇 What is a currying function?(tip #75)进一步说明:柯里化函数将一个「接收多个参数的函数」转变为「一次只接收一个参数的函数序列」,即 n 元函数变成一元函数串,最后一个函数汇总所有参数并返回结果。以三元乘法为例:

// Normal definition function multiply(a, b, c) { return a * b * c; }; console.log(multiply(1, 2, 3)); // Output: 6 // Simple curry function definition function multiply(a) { return (b) => { return (c) => { return a * b * c; }; }; }; console.log(multiply(1)(2)(3)); // Output: 6

可见柯里化的本质是「逐个接收参数,每接收一个参数返回一个新函数,直到所有参数集齐才真正执行」。

三、部分应用(Partial Application):先固定部分参数,生成参数更少的函数

3.1 数学定义

部分应用将一个函数

f: X * Y -> R

的第一个参数固定,产生一个新的函数

f': Y -> R

f'与f做的事相同,但只需要填写第二个参数,这就是为什么f'比f少一个参数(arity 少 1)。

3.2 代码示例:绑定第一个参数

例如:把函数add的第一个参数固定为 5,产生新函数plus5:

function plus5(y) { return 5 + y; } plus5(3); // returns 8

3.3 部分应用的规则与通用实现

部分应用使用一个二元函数和一个值,产生一个一元函数:

partApply: ((X × Y → R) × X) → (Y → R)

通用的部分应用实现(同样来自 第 28 期文档):

function partApply(f, x) { return function(y) { return f(x, y); } }

调用方式:partApply(add, 5)(3)返回8。与柯里化不同,partApply在一次调用中同时接收「函数」和「固定值」两个参数,立刻产出「参数更少的新函数」。

四、柯里化 vs 部分应用:一张表看清区别

维度柯里化(Currying)部分应用(Partial Application)
转换规则(X × Y → R) → (X → (Y → R))((X × Y → R) × X) → (Y → R)
输入一个函数一个函数 + 一个固定值
产物一元函数 →(再返回)一元函数直接得到一个一元函数
每次调用接收参数数1 个可以接收多个(函数 + 已固定值)
调用形态f(3)(5)partApply(f, 3)(5)
返回的新函数仍可能继续接收参数、继续柯里化参数个数已经确定减少,等待剩余参数
核心目的把多参调用改造成可分步、可延迟的链式调用预先「配置」部分参数,产出专用函数

一句话总结二者的差异(这也是 第 28 期 想传递的核心结论):

  • 柯里化:改变调用方式——「一次只喂一个参数」,每次调用都返回一个新函数;
  • 部分应用:改变参数数量——「一次性固定若干个参数」,产出一个参数更少的函数,之后只补剩余参数。

五、实战:柯里化与部分应用在真实代码中的用法

5.1 柯里化用于延迟执行与参数复用

柯里化最常见的价值是「分步传参」,例如按需生成带固定上下文的函数:

function log(level) { return function (message) { console.log(`[${level}] ${message}`); }; } const info = log('INFO'); const error = log('ERROR'); info('user logged in'); // [INFO] user logged in error('disk full'); // [ERROR] disk full

5.2 部分应用用于「配置化」函数

部分应用适合「先配置、后使用」的场景,例如预置税率、汇率或折扣:

function partApply(f, x) { return function(y) { return f(x, y); } } function calculatePrice(price, taxRate) { return price + price * taxRate; } // 固定税率 0.08,生成专用函数 const withTax = partApply(calculatePrice, 100); withTax(0.08); // 108

5.3 与原生bind的对应关系

JavaScript 原生的Function.prototype.bind本质上就是一种部分应用(同时还能绑定this)。仓库中的 Binding objects to functions(tip #61)展示了其语法:

fun.bind(thisArg[, arg1[, arg2[, ...]]])

其中arg1, arg2, ...就是「预置参数」,调用绑定后的函数时只需补足剩余参数——这正是部分应用的思想。因此实际开发中,你可以直接用add.bind(null, 5)实现plus5,而无需手写partApply。

六、如何继续在本仓库中深入学习

  • 本主题的多语言对照:繁体中文 2016-01-28-curry-vs-partial-application.md、简体中文 2016-01-28-curry-vs-partial-application.md、英文 2016-01-28-curry-vs-partial-application.md,便于对照阅读;
  • 柯里化的多元扩展:What is a currying function?(tip #75);
  • 部分应用的 Native 实现:bind详解见 Binding objects to functions(tip #61);
  • 仓库 README.md 的 Tips 列表中第 28 期条目即本主题(Currying vs partial application),可在官方博客中按期查阅。

结语

柯里化与部分应用是函数式编程中极易混淆的两个概念:柯里化重构的是「如何调用」——一次只传一个参数,形成函数串;部分应用重构的是「函数的形状」——预先固定参数,产出更专用的函数。理解二者的数学规则(curry与partApply的类型签名)后,你就掌握了判断标准:若想让调用变成f(3)(5)的分步形态,用柯里化;若想快速产出一个「参数更少」的专用函数,用部分应用(或直接使用bind)。这两种手法在事件处理、配置复用、函数组合等场景中都有着广泛的应用价值。

  • 教程

【免费下载链接】jstips

This is about useful JS tips!

项目地址:https://gitcode.com/gh_mirrors/js/jstips
点击查看免费下载
上一篇:解锁电视盒子潜能:ZXV10 B860AV3.2-M 变身Linux服务器完全刷机教程
下一篇:3个步骤解决HEIC缩略图不显示问题:Windows系统图像预览解决方案

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询