JavaScript 如何做函数柯里化

早上想喝奶茶,纠结选三分糖还是五分糖,到店后才发现店员总问你“要几分糖、要常温还是冰、加不加珍珠”,问得人头疼。后来你发现,要是提前跟店员说“我要一杯珍珠奶茶”,下次再买只要补一句“三分糖常温”就行——这其实跟JavaScript里的“函数柯里化”是一个道理,把复杂的“多条件提问”拆成了“分步说需求”,既不绕人,还能重复用步骤。

什么是函数柯里化?先从生活化例子拆明白

咱们先不用记复杂定义,拿点奶茶的事接着说:

JavaScript 如何做函数柯里化

  • 原来的普通点单函数是:点单(奶茶类型, 糖度, 温度, 配料),你每次点都得说全4个信息,比如点单("珍珠奶茶", "三分糖", "常温", "加珍珠"),重复点单时,“珍珠奶茶”和“加珍珠”这两个信息每次都得说,麻烦。
  • 柯里化后的点单函数是:点单(奶茶类型)(糖度)(温度)(配料),你可以先定“我要珍珠奶茶”,存成一个固定的“奶茶模板”——珍珠奶茶模板 = 点单("珍珠奶茶"),下次再点就只要说剩下的:珍珠奶茶模板("三分糖")("常温")("加珍珠"),甚至还能提前定好多个模板,比如“芋泥奶茶模板”“绿茶模板”,随便用。

简单说,柯里化就是把“一次传所有参数的函数”,拆成“每次传一个参数、返回新函数”的形式,让参数可以分步给,还能重复用前面固定的部分。

函数柯里化的核心作用:解决重复传参的麻烦

刚接触的人可能会觉得:不就是拆函数吗?有啥用?其实日常写代码里,柯里化能解决两个很常见的麻烦:

第一个是“减少重复参数”,比如你做了一个计算商品总价的函数:计算总价(商品单价, 数量, 运费),要是你买同一家店的3件衣服,每次都传同样的运费,就像每次点奶茶都要重复说“珍珠奶茶”一样;柯里化后,你可以先把“这家店的运费”固定:固定运费计算 = 计算总价(10, 12),每次买这家店的商品,只要传单价和数量就行,不用每次输运费。

第二个是“函数复用更灵活”,比如你写了一个发送短信的函数:sendSMS(手机号, 内容),要是你给同一个客户发多条通知,柯里化后先固定手机号:给张三发 = sendSMS("138xxxx1234"),之后只要给张三发("订单已发货")或给张三发("请查收快递"),不用每次都输手机号,代码更整洁。

用JavaScript写第一个柯里化函数,跟着步骤来

现在咱们用代码实现一个最基础的柯里化函数,不用怕看不懂,每一步都对应刚才的点单例子:

第一步:先写普通的多参数函数,比如刚才的点单:

`javascript

function 普通点单(类型, 糖度, 温度, 配料) {

return 一杯${糖度}${温度}${类型},加${配料};

}

`

第二步:把它改成柯里化函数,核心是“函数返回函数,直到参数传完才执行”:

`javascript

function 柯里化点单(类型) {

// 第一次传完类型,返回一个接收糖度的新函数

return function(糖度) {

// 第二次传完糖度,返回接收温度的新函数

return function(温度) {

// 第三次传完温度,返回接收配料的新函数

return function(配料) {

// 所有参数传齐,返回最终结果

return 一杯${糖度}${温度}${类型},加${配料};

}

}

}

}

`

第三步:用起来就像咱们刚才说的模板:

`javascript

// 先定珍珠奶茶模板

const 珍珠奶茶 = 柯里化点单("珍珠奶茶");

// 再定这个模板的三分糖常温版本

const 三分糖常温珍珠奶茶 = 珍珠奶茶("三分糖")("常温");

// 最后补配料,得到最终结果

console.log(三分糖常温珍珠奶茶("加珍珠"));

// 输出:一杯三分糖常温珍珠奶茶,加珍珠

`

是不是很简单?要是你传的参数少,比如只传了两个,那返回的还是新函数,等参数够了再执行就行,不用纠结“传几个才对”。

柯里化的小提醒:别过度使用

柯里化虽然好用,但不是所有场景都适合,要是函数只有1个或2个参数,拆成柯里化反而会让代码变复杂,就像你买一杯奶茶,没必要提前定模板,直接说清楚就行;只有当你需要重复用部分参数,或者要灵活组合函数的时候,柯里化才是最优选择。

上一篇 TypeScript 基本类型有哪些