ES6如何用一句代码实现函数的柯里化

 更新时间:2020年01月18日 16:46:32   作者:艾伦叔叔  
这篇文章主要介绍了ES6如何用一句代码实现函数的柯里化,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

柯里化是干什么的?首先看看下面这个函数

let store = (a,b,c) => "这是你的七仔面" 
//函数就好像一个小卖部,一碗七仔面要三张软妹币:a,b,c (五个参数)

那函数柯里化是什么?就是我们买面吃的过程可能是这样:

let curryStore = curry(store) //刚刚的小卖部被柯里化了

//最佳状况
curryStore(1,5,1)// 老板,刚好!不用找了,刚好七块钱。老板: "这是你的七仔面" 

//偶尔出现的情况
let boss = curryStore(5) //老板,这五块钱你先拿着,我找找有没有一块钱。老板:……
boss = boss(1) //有了老板,这一块钱你先拿着,我找找还有没有一块钱。。老板:……
boss(1) //哈哈,终于找到了,给!老板:"这是你的七仔面" 

curryStore(5)(1)(1) //等价于上诉情况

所以这里我们可以看到,函数柯里化,是可以用来慢慢凑齐参数,延迟函数的执行。(先分期交钱,后交货!)

做个题

现在,我们的目标是实现一个curry 函数,达到以下使用效果:
在给到足够的参数时,执行函数。不够参数的时候则返回一个新的curry函数。

let curryPlus = curry((a,b,c) => a+b+c) //这里给到一个有三个参数的函数

curryPlus(1)(2)(3) //返回 6
curryPlus(1)(2,3) //返回 6
curryPlus(1,2)(3) //返回 6

let x = curryPlus(1)(2) //喂,怎么才两个参数?返回一个curry函数(已经带了两个参数)
x(1) //返回 4
x(2) //返回 5

作为一个js很厉害的人,这种问题用一行代码解决不是问题,问题是我没那么厉害。。。

于是,我们先从土方法说起吧orz

按照curry的用法,原理是返回了一个函数,这个函数的参数个数不确定(你可能同时掏出两张一块钱),于是我们可以运用不定参数的写法:

const curry = (fn) => {
  return (...args) =>{ //不定参数,想给多少给多少
    //给钱交货环节
  }
}

柯里化函数需要记住你已经给过他的参数,如果没给的话,则默认为一个空数组:

const curry = (fn,arr=[]) => { //arr数组用于记录已有参数
  return (...args) =>{  
    //给钱交货环节
  }
}

接下来每次调用的时候,需要检查参数是否给够,如果够了,则执行fn,没有的话则返回一个新的curry函数,将现有的参数塞给他:

const curry = ( fn, arr = []) => {
  return (...args) => { 

    //判断参数总数是否和fn参数个数相等
    if([...arr, ...args].length === fn.length){
      return fn(...arr, ...args) //拓展参数,调用fn
    }else{
      return curry(fn,[...arr, ...args]) //迭代,传入现有的所有参数
    }

  }
}

到这里,其实我们已经实现了curry函数。

接下来就是要看看怎么写才能更简洁。
首先,中间的代码可以写成一个立即执行函数,省掉一些...arr, ...args:

const curry = ( fn, arr = []) => {
  return (...args) => { 

    return ( a => {  //a是一个数组
      if(a.length === fn.length) {
        return fn(...a)
      }else{
        return curry(fn, a)
      }
    })([...arr, ...args]) //这里把arr和args摊开成一个数组赋值给a

  }
}

if语句可以缩减成三元表达式,也可以省掉很多字啦:

const curry = ( fn, arr = []) => {
  return (...args) => { 

    return ( a => { 

      return a.length === fn.length ? fn(...a) : curry(fn, a)

    })([...arr, ...args]) 

  }
}

最后,既然函数里啥事都没干,就只是return的话,不妨使用箭头函数最省的写法 input => output, 把return和大括号都给省了:

const curry = ( fn, arr = []) => {
  return (...args) => { 
    return ( a => a.length === fn.length? fn(...a) : curry(fn, a))([...arr, ...args])  //先折叠一层
  }
}

再折叠:

const curry = ( fn, arr = []) => {
  return (...args) => ( a => a.length === fn.length? fn(...a) : curry(fn, a))([...arr, ...args])  //再折叠
}

收工了收工了:

const curry = ( fn, arr = []) => (...args) => ( a => a.length === fn.length? fn(...a) : curry(fn, a))([...arr, ...args]) 
//衣服给您叠好了

拿去试试:

const curry = ( fn, arr = []) => (...args) => ( a => a.length === fn.length? fn(...a) : curry(fn, a))([...arr, ...args])
let curryPlus = curry((a,b,c,d)=>a+b+c+d)

curryPlus(1,2,3)(4) //返回10
curryPlus(1,2)(4)(3) //返回10
curryPlus(1,2)(3,4) //返回10

当然了,柯里化函数的主要作用还是延迟执行,执行的触发条件不一定是参数个数相等,也可以是其他的条件,例如参数个为0的情况,那么我们需要对上面curry函数稍微做修改:

const curry = ( fn, arr = []) => (...args) => ( (a,b) => b.length === 0? fn(...a) : curry(fn, a))([...arr, ...args],[...args])
let curryPlus = curry((...x)=>x.reduce((a,b)=>a+b))

curryPlus(1) //返回一个函数
curryPlus(1)(2) //返回一个函数

//遇到参数个数为0的情况才执行
curryPlus(1)(2)(4)() //返回7
curryPlus(1,2)(4)() //返回7

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • JavaScript将字符串转换为整数的方法

    JavaScript将字符串转换为整数的方法

    这篇文章主要介绍了JavaScript将字符串转换为整数的方法,涉及javascript中parseInt函数的使用技巧,非常具有实用价值,需要的朋友可以参考下
    2015-04-04
  • JS实现关键字搜索时的相关下拉字段效果

    JS实现关键字搜索时的相关下拉字段效果

    关键字搜索时有下拉字段,在使用百度时会遇到,本例讲述用js实现类似的效果
    2014-08-08
  • javascript实现文字跑马灯效果

    javascript实现文字跑马灯效果

    这篇文章主要为大家详细介绍了javascript实现文字跑马灯效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-06-06
  • js实现Select列表内容自动滚动效果代码

    js实现Select列表内容自动滚动效果代码

    这篇文章主要介绍了js实现Select列表内容自动滚动效果的方法,涉及javascript简单递归调用遍历select及时间函数的相关使用技巧,需要的朋友可以参考下
    2015-08-08
  • JavaScript中你不知道的Object.entries用法

    JavaScript中你不知道的Object.entries用法

    大家应该都知道,Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致,这篇文章主要给大家介绍了关于JavaScript中你不知道的Object.entries用法的相关资料,需要的朋友可以参考下
    2021-10-10
  • electron-builder打包配置详解

    electron-builder打包配置详解

    本文主要介绍了electron-builder打包配置详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • JS数组去重的常用方法总结

    JS数组去重的常用方法总结

    这篇文章主要给大家介绍了关于js数组去重的常用方法,js数组去重是比较常见的数组操作方式之一,文中介绍了九种常用方法,需要的朋友可以参考下
    2023-10-10
  • JavaScript通过字符串调用函数的实现方法

    JavaScript通过字符串调用函数的实现方法

    这篇文章主要介绍了JavaScript通过字符串调用函数的实现方法,实例分析了javascript动态调用函数的技巧,需要的朋友可以参考下
    2015-03-03
  • javascript模拟枚举的简单实例

    javascript模拟枚举的简单实例

    本篇文章主要是对javascript模拟枚举的简单实例进行了介绍,需要的朋友可以过来参考下,希望对大家有所帮助
    2014-03-03
  • 面向JavaScript入门初学者的二叉搜索树算法教程

    面向JavaScript入门初学者的二叉搜索树算法教程

    二叉搜索树则是二叉树的一种,但它只允许你在左侧节点储存比父节点小的值,右侧只允许储存比父节点大的值,这篇文章主要给大家介绍了关于JavaScript二叉搜索树算法的相关资料,需要的朋友可以参考下
    2021-09-09

最新评论