未加星标

一行写出javascript函数式编程中的curry

字体大小 | |
[前端(javascript) 所属分类 前端(javascript) | 发布者 店小二03 | 时间 2017 | 作者 红领巾 ] 0人收藏点击收藏

最近在学习javascript函数式编程,对其中大名鼎鼎的curry十分感兴趣,curry函数可以接受一个函数,我们暂且称之为原始函数,返回的也是一个函数,柯里化函数,这个返回的柯里化函数功能十分强大,他在执行的过程中,不断的返回一个贮存了传入参数的函数,直到触发了原始函数执行的条件。这么说比较概括,那么就举个例子来说明一下:

原始函数:

var add = (x, y) => x + y

柯里化函数:

var curryAdd = curry(add)

这个add需要两个参数,但是我们的curryAdd执行可以传入更少的参数,当传入的参数少于add需要的参数的时候,add函数并不会执行,curryAdd就会将这个参数记下来,并且返回另外一个函数,这个函数可以继续执行传入参数,我们会有一个变量专门记录传入参数的情况,如果传入参数的总数等于add需要参数的总数,我们就激活了原始参数执行,就会返回我们想要的结果。

// 此时只传入了一个参数 根据判断返回的是一个函数 var add2 = curryAdd(2) // add2 = function(...) {} // 此时累计传入了两个参数 等于了add需要参数的总和 所以返回的是一个结果 // 相当于执行了add(2)(3) var result = add2(3) // result = 5

还是很不错的是吧,好吧,我们的目的是为了写出这个神奇curry函数,而且还要一行写出来,不要着急,先分析一下怎么去写,然后再一步步的优化。

那根据上面的描述,我们看一下curry函数需要什么,首先需要一个变量,用来存下来原始函数的参数个数,我们知道function有一个属性为length,对就是它,我们用limit存下来

var curry = function(fn) { var limit = fn.length ... }

curry函数要返回一个函数, 这个函数是要执行的,那么问题就是,我们要判断这个函数的执行是否激活了原始函数的执行,问题就出现在传入的参数上面。返回函数还是结果?这的确是一个问题

我们先写返回结果的情况,当传入的参数等于原始函数需要的参数时,我们执行原始函数fn

var curry = function(fn) { var limit = fn.length return function (...args) { if (args.length >= limit) { return fn.apply(null, args) } } }

否则呢 我们就要返回一个贮存了参数的函数,这里有亮点,一是参数的传入历史我们要记录下来,而是这个返回的函数需要做些什么

var curry = function(fn) { var limit = fn.length return function (...args) { if (args.length >= limit) { return fn.apply(null, args) } else { return function(...args2) { } } } }

看出来了吧 我们只需要把返回函数执行的参数累加起来就达到了记录参数传入情况的目的,于是我们想到了concat 对 args.concat(args2), 依次类推,我们返回的函数要做的就是重复做上面的事情,也就是参数为args的函数要做的事情,所以他需要一个名字,不然我们没法执行,我们叫它judgeCurry

所以正如我们所说的,要么返回一个函数,要么执行原始函数。

var curry = function(fn) { var limit = fn.length return function judgeCurry (...args) { if (args.length >= limit) { return fn.apply(null, args) } else { return function(...args2) { return judgeCurry.apply(null, args.concat(args2)) } } } }

我们终于写完了这个神奇的curry函数,它真的很强大,配合compose,那真是一个字,爽。

我们的目的还是一行把上面那个函数写出来,一行写?怎么写?对了,用ES6啊,于是一番折腾

var currySingle = fn => judgeCurry = (...args) => args.length >= fn.length ? fn.apply(null, args) : (...args2) => judgeCurry.apply(null, args.concat(args2))

好,我们看一下哪有问题,对了,就是我们为了不用limit参数,用了就得赋值,赋值就不能一行搞定了,就会变成这样

var currySingle = fn => { var limit = fn.length var judgeCurry = null return judgeCurry = (...args) => args.length >= limit ? fn.apply(null, args) : (...args2) => judgeCurry.apply(null, args.concat(args2)) }

需要判断参数的时候不断的对fn.length求值,但是fn.length的值是确定的,我们不想每次都求值,但又不想用limit怎么办,有什么办法呢?你一定想到了,立即执行函数!!

var currySingle = fn => ((limit) => judgeCurry = (...args) => args.length >= limit ? fn.apply(null, args) : (...args2) => judgeCurry.apply(null, args.concat(args2)))(fn.length)

不得不感叹javascript的神奇,终于,我们就一行将这个神奇的curry写出来了。。。

本文前端(javascript)相关术语:javascript是什么意思 javascript下载 javascript权威指南 javascript基础教程 javascript 正则表达式 javascript设计模式 javascript高级程序设计 精通javascript javascript教程

主题: 函数式编程中大变量
分页:12
转载请注明
本文标题:一行写出javascript函数式编程中的curry
本站链接:http://www.codesec.net/view/529761.html
分享请点击:


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 前端(javascript) | 评论(0) | 阅读(69)