一道题看透函数柯里化(currying)
来源:互联网 发布:产品经理 原型软件 编辑:程序博客网 时间:2024/06/05 07:01
对于函数的柯里化(currying)应该不陌生,简单来说 Currying 技术是一种通过把多个参数填充到函数体中,实现将函数转换为一个新的经过简化的(使之接受的参数更少)函数的技术。当发现正在调用同一个函数时,并且传递的参数绝大多数都是相同的,那么用一个Curry化的函数是一个很好的选择.
下面利用闭包实现一个curry化的加法函数, 我们简单理解一下 curry 化:
function add(x, y){ if(x && y) return x + y; if(!x && !y) throw Error("Cannot calculate"); return function(newx){ return x + newx; };}add(3)(4); //7add(3, 4); //7var newAdd = add(5);newAdd(8); //13var add2000 = add(2000);add2000(100); //2100
这样做其实很类似 bind:
function add(a, b){ console.log(a+b); return a + b;}add(3, 4); //7add.bind(null, 3)(4); //7var newAdd = add.bind(null, 5);newAdd(8); //13var add2000 = add.bind(null, 2000);add2000(100); //2100
同理也可以使用 call 和 apply, 因为他们可以实现 bind 的功能:
Function.prototype.bind = function(context){ var _this = this; var args = [].slice.call(arguments, 1); return function (){ innerArgs = [].slice.call(arguments); if(innerArgs && innerArgs.length > 0) args.push.apply(args, innerArgs); return _this.apply(context, args); }}add(3, 4); //7add.bind(null, 3)(4); //7var newAdd = add.bind(null, 5);newAdd(8); //13var add2000 = add.bind(null, 2000);add2000(100); //2100
但是,如果看到了这个题:
实现一个函数sum,运算结果可以满足如下预期结果:
sum(1,2,3); //6sum(2,3)(2); //7sum(1)(2)(3)(4); //10sum(2)(4,1)(2); //9
还觉得简单么?我们理一下思路。首先试想一下这个 sum 函数的结构:
function sum(){ return function(){ return function(){ //... } }}
这个函数返回的一定是个函数,但貌似需要写无限个,这个不合理,我们修改一下:
function sum(){ function innerSum(){ //... return innerSum(); } return innerSum();}
这样一来每次调用就不需要定义无限个函数了。我们完善里面的代码:
//sum(1,2,3); //6//sum(2,3)(2); //7//sum(1)(2)(3)(4); //10//sum(2)(4,1)(2); //9function sum(){ var cur = [].slice.call(arguments).reduce(function(a,b){return a+b;},0); function innerSum(){ var next = [].slice.call(arguments).reduce(function(a,b){return a+b;},0); cur += next; return innerSum; } return innerSum;}
这样 sum 函数的柯里化过程就完成了,但是这个函数的返回的总是一个函数,这样我们如何输出数值呢?我们可以借助隐式类型转换需要的 toString 函数实现:
function sum(){ var cur = [].slice.call(arguments).reduce(function(a,b){return a+b;},0); function innerSum(){ var next = [].slice.call(arguments).reduce(function(a,b){return a+b;},0); cur += next; return innerSum; } innerSum.toString = function(){ return cur; } return innerSum;}console.log(sum(1,2,3)); //6console.log(sum(2,3)(2)); //7console.log(sum(1)(2)(3)(4)); //10console.log(sum(2)(4,1)(2)); //9
计算结果没错,我们还可以换作 valueOf 实现:
function sum(){ var cur = [].slice.call(arguments).reduce(function(a,b){return a+b;},0); function innerSum(){ var next = [].slice.call(arguments).reduce(function(a,b){return a+b;},0); cur += next; return innerSum; } innerSum.valueOf = function(){ return cur; } return innerSum;}console.log(sum(1,2,3)); //6console.log(sum(2,3)(2)); //7console.log(sum(1)(2)(3)(4)); //10console.log(sum(2)(4,1)(2)); //9
其实,如果同时存在 toString 和 valueOf 系统会先调用 valueOf, valueOf 返回的不是对象或 undefined 的话,就不再调用 toString 了,返回值自然是 valueOf 的返回值。这个很基础,这里就不提了。
通用柯里化方法
通用的柯里化写法其实比之前的 sum 函数要简单许多
var currying = function(fn) { // 主要还是收集所有需要的参数到一个数组中,便于统一计算 var args = [].slice.call(arguments, 1); return function(){ var _args = args.concat([].slice.call(arguments)); return fn.apply(null, _args); }}var sum = function(){ var args = [].slice.call(arguments); return args.reduce(function(a, b) { return a + b; });};var sum10 = currying(sum, 10);console.log(sum10(20, 10)); // 40console.log(sum10(10, 5)); // 25
阅读全文
1 0
- 一道题看透函数柯里化(currying)
- 函数柯里化(Currying)
- Scala 函数柯里化(Currying)
- 函数柯里化function currying
- Scala 函数柯里化(Function currying)
- Swift函数柯里化(Currying)简谈
- 函数-JavaScript 中的 函数 currying 柯里化
- 前端开发者进阶之函数柯里化Currying
- 前端开发者进阶之函数柯里化Currying
- 函数式编程概念:柯里化(currying)
- 什么是js函数的currying /柯里化?
- 函数式中的 currying
- 函数式中的Currying
- JavaScript函数绑定Demo以及函数Currying柯里化
- 柯里化(Currying)
- Swift 柯里化(Currying)
- Currying-柯里化[Swift笔记]
- Swift柯里化(Currying)
- 闭包
- [bzoj 1103] 大都市meg(树状数组和dfs序)
- 蓝桥杯----生成回文数
- android 四大组件只------BroadCastReceiver(广播)
- C语言基础-指针深入16
- 一道题看透函数柯里化(currying)
- Unity导入STL格式模型(二)
- RecyclerView做ListView的效果,Recyclerview带分隔线的使用
- Tour UVA
- iOS 第三方应用中打开自己的文件(UIDocumentInteractionController)
- 鸡啄米:添加控件变量
- 一、Servlet基础
- jQuery选择器之表单元素选择器
- graph确定是否有循环