未加星标

从 sum(2)(3) == sum(2, 3) 到实现柯里化函数

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

一道前端笔试题如下:写出一个满足 sum(2, 3) == 5 且 sum(2)(3) == 5 的 sum 函数。

只是完成题目本身,并没有什么难度,只是考察 JS 中如何判断输入的函数参数个数,并且将函数作为返回值返回而已。一个简单的实现如下:

function sum(){ if (arguments.length > 1) { return arguments[0] + arguments[1]; } else { var a = arguments[0]; return function(x){ return a + x; } } }

进阶一点的题目版本应该是这样的:实现一个 sumOf3(a, b, c) 函数,使得下面的几种调用都返回 6:

sumOf3(1)(2)(3) sumOf3(1, 2)(3) sumOf3(1)(2, 3) sumOf3(1, 2, 3)

很好,参数个数增加的时候,上面的解法就离组合爆炸不远了。再将这个问题一般化,就得到了更有意义的问题:能否实现一个一共需要 n 个参数的函数,使得这 n 个参数可以分多次函数调用依次传入呢?

直接写出这样的函数无疑是麻烦的。不过我们可以写出用于生成这个函数的函数,这就是所谓的高阶函数了。

现在我们有一个原函数 sumOf4 的实现如下:

function sumOf4(a, b, c, d){ return a + b + c + d; }

我们想要构造出一个 sum4 函数,使得如下的调用都能返回 10:

sum4(1, 2, 3, 4) sum4(1, 2)(3, 4) sum4(1)(2, 3, 4) sum4(1)(2)(3, 4) sum4(1)(2)(3)(4)

为了生成这个 sum4 函数,我们需要将原本接受 4 个固定参数的 sumOf4 函数改造成一个能分次传入参数的函数。对实现这个过程的函数而言,其输入是 sumOf4 函数,输出是 sum4 函数。所以,这个函数实现了将普通函数 sumOf4 转化为能分次接受参数的柯里函数 sum4 ,因此称这个函数为柯里化函数。

实现思路并不复杂,只需要递归的基本思路:递归检查参数是否达到指定的长度。如一开始指定 5 个参数,第一次调用时给了 2 个,那么就递归地返回一个新函数,这个新函数检查给自己的参数够不够剩下的 3 个,再传 1 个参数调用这个新函数时,它就返回一个检查参数够不够 2 个的函数。一直到检查到参数终于凑满 5 个时,就执行原函数返回。代码如下:

function curry(fn, argLen, currArgs){ return function(){ var args = [].slice.call(arguments); // 首次调用时未提供最后一个参数 if (currArgs !== undefined) { args = args.concat(currArgs); } // 递归出口 if (args.length == argLen) { return fn.apply(this, args); } else { return curry(fn, argLen, args); } } } function sumOf4(a, b, c, d){ return a + b + c + d; } // 改造普通函数,返回柯里函数 var sum4 = curry(sumOf4, 4); console.log(sum4(1, 2, 3, 4)); // 10 console.log(sum4(1, 2)(3, 4)); // 10 console.log(sum4(1)(2, 3, 4)); // 10 console.log(sum4(1)(2)(3, 4)); // 10 console.log(sum4(1)(2)(3)(4)); // 10

由此可见 JS 中函数式编程的强大。譬如如果存在一个函数,其参数需要通过多次 Ajax 请求来获取。那么在使用这个函数时,可通过 curry 这一柯里化函数,将原函数拆分,从而在多次请求的响应中逐次传入所有参数。当然,链式调用也能实现同样的需求,这个柯里化函数本身也只是一个比较优雅的 Proof of Concept 而已。

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

主题: 函数式编程Ajax需求出口
分页:12
转载请注明
本文标题:从 sum(2)(3) == sum(2, 3) 到实现柯里化函数
本站链接:http://www.codesec.net/view/482064.html
分享请点击:


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