curry柯里化

首先咱们先来看一个问题,如果实现一个add函数,可实现上面的性能

add(1,2,3) // 6add(1)(2)(3) // 6add(1,2)(3) // 6add(1,2,3,4)(5)(6,7) // 28

当然了,所须要用到的知识点便是柯里化。

首先看下柯里化定义:
用于缓存函数参数的一种形式;给函数分步传递参数,每次传递局部参数,并返回一个更具体的函数接管剩下的参数,这两头可嵌套多层这样的接管局部参数的函数,直至返回最初后果。

初看下面这行字,可能不太好了解,我大略总结了下,如何去实现或者说去了解柯里化,大抵是上面两点。

1、如何进行参数的缓存
2、在何时执行原函数
当收集到所须要的参数时,便去执行指标函数,失去后果,否则持续收集参数。

这里就不展开讨论闭包、call、apply、bind这些概念了。

举个例子

function add(a,b,c) {  console.info(a, b, c, '==此函数须要传递三个参数执行==)  return a + b + c}

不难看出下面的函数执行须要三个参数,因而咱们在调用test时,须要传递a,b,c否则函数执行异样;这时候回到下面的两点,如何进行参数的缓存以及何时执行原函数去失去指标后果。

接下来看看如何去实现

固定参数个数的柯里化

/** * 传入固定参数长度的柯里化 * @params fn 原函数 * @params  args 初始化参数 */function curry(fn, ...args) {  const len = fn.length  return function() {    // 参数收集    const allArgs = [...args, ...arguments]    // 达到目标参数个数后,执行原函数    if (allArgs.length >= len) {      return fn.apply(null, allArgs)    }    return curry.call(null, fn, ...allArgs)  }}function add(a,b,c) {  return [...arguments].reduce((pre, cur) => pre += cur, 0)}const test = curry(add)console.info(test(1,2,3)) // 6console.info(test(1,2)(3)) // 6console.info(test(1)(2)(3)) // 6test = null // 避免内存透露

参数不固定

1、当传入空的参数时,执行原函数
/** * 传入参数不固定,参数为空时执行函数的柯里化 * @params fn 原函数 * @params  args 初始化参数 */function _curry(fn, ...args) {  let allArgs = [...args]  return function next(..._args) {    allArgs = [...allArgs, ..._args]    if (_args.length === 0) {      return fn.apply(null, allArgs)    }    return next  }}function _add() {  return [...arguments].reduce((pre, cur) => pre += cur, 0)}const _test = _curry(_add)_test(1,2)_test(3)console.info(_test()) // 6_test(4)console.info(_test()) // 10_test = null // 避免内存透露
2、间接返回

这里须要用到一个小知识点,在解析函数的原始值时,会用到函数的隐式转换toString,因而咱们的执行原函数节点在于toString

/** * 传入参数不固定柯里化 * @params fn 原函数 * @params  args 初始化参数 */function _curry(fn, ...args) {  let allArgs = [...args]  function next(..._args) {    allArgs = [...allArgs, ..._args]    return  _curry.call(null, fn, ...allArgs)  }  next.toString = function() {    return fn.apply(null, allArgs)  }  return next}function _add() {  return [...arguments].reduce((pre, cur) => pre += cur, 0)}const _test = _curry(_add)_test(1, 2) // 2_test(4)(5)(6) // 15console.info(_test()) // 10_test = null // 避免内存透露

上述便是柯里化用于提早执行的几种用法

参数复用

可能了解上述用法后,柯里化用于参数复用就轻而易举了,如下例

/** * Object.prototype.toString.call(obj) === '[object ***]' */function typeOf(value) {  return function(obj) {    const toString = Object.prototype.toString    const map = {      '[object Boolean]': 'boolean',      '[object String]': 'string',      '[object Number]': 'number',      '[object Function]': 'function',      '[object Array]': 'array',      '[object Date]': 'date',      '[object RegExp]': 'regExp',      '[object Undefined]': 'undefined',      '[object Null]': 'null',      '[object Object]': 'object'    }    return map[toString.call(obj)] === value  }}const isNumber = typeOf('number')const isString = typeOf('string')isNumber(0) // trueisString('a') // true