【你应该了解的】函数柯里化
一道面试题
已知一个add方法。
1 | function add(a, b, c) { |
实现一个sum方法,满足如下条件:
1 | sum(1)(2,3) // 6 |
该题其实就运用了函数柯里化的思想,我们可以将add方法通过函数柯里化转化为sum方法。
先来看看什么是函数柯里化。
什么是函数柯里化
维基百科中这样定义柯里化:
在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
用大白话来说就是:只传递给函数一部分参数来调用它,让它返回一个新函数去处理剩下的参数。
举个例子理解柯里化:
假设你有一间商店,促销季,你想给普通顾客所有商品九折优惠。
1 | function setDiscount(price, discount) { |
当一个普通顾客买了一件价格为100元的商品,你计算价格可以:
1 | const price = setDiscount(100, 0.9); |
你会发现,每次计算一个商品价格,都需要输入价格和折扣,很麻烦。
1 | const price1 = setDiscount(500, 0.9); |
我们可以将函数setDiscount柯里化,避免每次都输入折扣。
1 | function currySetDiscount(discount) { |
现在我们可以这样计算普通顾客购买商品时的价格:
1 | const price = setNinetyPercent(500); |
同样的,针对VIP顾客,所有商品打八折,可以这样计算:
1 | const setEightyPercent = currySetDiscount(0.8); |
函数柯里化的这种作用,可以理解为参数复用,延迟执行,减少了代码冗余,增加了代码可读性。
函数柯里化的简单实现
回到开始的那道题,我们来写一个curry函数。
1 | function curry(fn, args) { |
原理:用闭包保存参数,当参数数量和原函数参数数量一致时,执行函数。
可以这样来柯里化add,生成sum方法:
1 | var sum = curry(add); |
函数柯里化的应用
延迟计算
我们常用的bind函数。
1 | let obj = { |
这里bind用来改变函数执行时的上下文,但是函数本身并不执行,所以本质上是延迟计算。
我们看下bind的模拟实现,本质上就是一种柯里化。
1 | function myBind(){ |
总结
函数柯里化是函数式编程(一种编程范式)中的一个最基本的运算,它生于函数式编程,也主要服务于函数式编程(函数的组合前提是需要单参数的函数)。我们日常开发中其实无需特意区分是否使用函数柯里化,闭包,高阶函数等都一定程度上与函数柯里化有异曲同工之妙。