js函数柯里化(function currying)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27626333/article/details/79628326

  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

  柯里化是高阶函数应用中的一种,此处稍微介绍一下高阶函数,高阶函数是指至少满足下列条件之一的函数:

  • 函数可以作为参数被传递
  • 函数可以作为返回值输出

猜你喜欢

转载自blog.csdn.net/qq_27626333/article/details/79628326