currying又称部分求值。一个currying的函数首先会接受一些参数,接受了这些参数之后,该函数不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正求值的时候,之前传入的所有参数都会被一次性用于求值。
currying简单的说就是:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。你可以一次性地调用 curry 函数,也可以每次只传一个参数分多次调用。
下面先用一个简单的例子实现函数柯里化:
let add = function(x, y){
return x + y
}
把add函数柯里化成这样:
var addCurrying = function(x) {
return function(y) {
return x + y
}
}
var increment = addCurrying(1)
var addTen = addCurrying(10)
increment(2)
// 3
addTen(2)
// 12
addCurrying 函数接受一个参数并返回一个新的函数。调用 addCurrying 之后,返回的函数就通过闭包的方式记住了 addCurrying 的第一个参数x。currying函数可以复用一些传入的参数,形成闭包保存在函数内,调用时只需要传入变化的数据。
/**
* @description 柯里化函数
* @param {Function} fn 传入的需要运算的函数
* @return {Function} 返回函数
*/
let curry = function (fn) {
// args保存需要复用的参数
let reuseArgs = Array.prototype.slice.call(arguments, 1)
return function () {
// selfArgs是自身参数
let selfArgs = Array.prototype.slice.call(arguments)
// 合并自身参数和复用的参数
let mergeArgs = reuseArgs.concat(selfArgs)
// 计算返回结果
return fn.apply(null, mergeArgs)
}
}
/**
* @description 求和
* @return {Number} 求和的值
*/
let add = function () {
let args = Array.prototype.slice.call(arguments)
let sum = 0
for (let i = 0; i < args.length; i++) {
sum += args[i]
}
return sum
}
// 3, 4, 5是固定不变,可复用的参数
let curryAdd = curry(add, 3, 4, 5)
curryAdd(6) // 结果为18
curryAdd(7, 8) // 结果为27
假设我们要编写一个计算每月的开销函数。每天结束之前,我们都要记录今天花掉了多少钱。
let monthlyCost = 0
let cost = function (money) {
monthlyCost += money
}
cost(100) // 第1天的开销
cost(200) // 第2天的开销
cost(300) // 第3天的开销
cost(500) // 第30天的开销
console.log(monthlyCost) // 1100
我们其实并不太关心每天花掉了多少钱,只是想知道到了月底的时候总共花掉了多少钱;所以每个月的前29天,我们都只要保存好当天的开销就行了,不要进行计算,到了第30天才进行求值计算,得到当月的开销。currying函数在参数复用的同时可以实现延迟计算。
/**
- @description 计算当月的开销
- @return {Number} 返回计算值
*/
let cost = function () {
let money = 0
for (let i = 0; i < arguments.length; i++) {
money += arguments[i]
}
return money
}
/**
- @description 柯里化函数
- @param {Function} fn 传入的需要运算的函数
- @return {Function} 返回函数
*/
let currying = function (fn) {
// args保存需要复用的参数
let reuseArgs = Array.prototype.slice.call(arguments, 1)
// 定义一个保存复用参数和自身参数的数组
let args = reuseArgs
return function () {
// arguments是自身参数
if (arguments.length === 0) {
return fn.apply(null, args)
} else {
[].push.apply(args, arguments)
}
}
}
let costCurrying = currying(cost)
costCurrying(100) // args为[100] 未真正求值
costCurrying(200) // args为[100, 200] 未真正求值
costCurrying(300) // args为[100, 200, 300] 未真正求值
costCurrying(500) // args为[100, 200, 300, 500] 未真正求值
console.log(costCurrying()) // 求值并输出结果:1100
柯里化是高阶函数应用中的一种,此处稍微介绍一下高阶函数,高阶函数是指至少满足下列条件之一的函数:
- 函数可以作为参数被传递
- 函数可以作为返回值输出