函数柯里化

来源:互联网 发布:php网教视频网站源码 编辑:程序博客网 时间:2024/05/16 10:15

含义:柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
因此柯里化的过程是逐步传参,逐步缩小函数的适用范围,逐步求解的过程。

柯里化一个求和函数

var add = function (a, b, c) {    return a+b+c;};var addCurrying= function(a) {    return function (b) {        return function (c) {            return a+b+c;        };    };};console.log(add(1,2,3));  //6console.log(addCurrying(1));//functionconsole.log(addCurrying(1)(2));//functionconsole.log(addCurrying(1)(2)(3)); //6

这里写图片描述

可以看到, addCurrying(1) 是一个 Function,每次调用都返回一个新的函数,该函数接受另一个调用,然后又返回一个新的函数,直至最后返回结果,分布求解,层层递进。(PS:这里利用了闭包的特点)

那么现在我们更进一步,如果要求可传递的参数不止3个,可以传任意多个参数,当不传参数时输出结果?

首先来个普通的实现:

//归并var add = function(items){    return items.reduce(function(a,b){        return a+b    });};console.log(add([1,2,3,4]));   //10

但如果要求把每个数乘以10之后再相加,那么:

var add = function (items,multi) {    return items.map(function (item) {        return item*multi;    }).reduce(function (a, b) {        return a + b    });};console.log(add([1, 2, 3, 4],10));  //100

好在有 map 和 reduce 函数,假如按照这个模式,现在要把每项加1,再汇总,那么我们需要更换map中的函数。

下面看一下柯里化实现:

var add = function () {    var _args = [];    return function () {        if (arguments.length === 0) {            return _args.reduce(function (a, b) {                return a + b;            });        }        [].push.apply(_args, [].slice.call(arguments));        return arguments.callee;    }};    var sum = add();console.log(sum);     // Functionsum(100,200)(300);    // 调用形式灵活,一次调用可输入一个或者多个参数,并且支持链式调用sum(400);console.log(sum());   // 1000 (加总计算) 

这里写图片描述

上面 add是柯里化了的函数,它返回一个新的函数,新的函数接收可分批次接受新的参数,延迟到最后一次计算。

通用的柯里化函数

var curry = function(fn) {    var _args = []    return function cb() {        if (arguments.length == 0) {            return fn.apply(this, _args)        }        Array.prototype.push.apply(_args, arguments);        return cb;    }}

柯里化的基础

上面的代码其实是一个高阶函数(high-order function), 高阶函数是指操作函数的函数,它接收一个或者多个函数作为参数,并返回一个新函数。此外,还依赖与闭包的特性,来保存中间过程中输入的参数。即:

1.函数可以作为参数传递
2.函数能够作为函数的返回值
3.闭包

柯里化的作用

1.延迟计算。上面的例子已经比较好低说明了。

2.参数复用。当在多次调用同一个函数,并且传递的参数绝大多数是相同的,那么该函数可能是一个很好的柯里化候选。

3.动态创建函数。这可以是在部分计算出结果后,在此基础上动态生成新的函数处理后面的业务,这样省略了重复计算。或者可以通过将要传入调用函数的参数子集,部分应用到函数中,从而动态创造出一个新函数,这个新函数保存了重复传入的参数(以后不必每次都传)。例如,事件浏览器添加事件的辅助方法:

var addEvent = function(el, type, fn, capture) {     if (window.addEventListener) {         el.addEventListener(type, function(e) {             fn.call(el, e);         }, capture);     } else if (window.attachEvent) {         el.attachEvent("on" + type, function(e) {             fn.call(el, e);         });     }  };

每次添加事件处理都要执行一遍 if…else…,其实在一个浏览器中只要一次判定就可以了,把根据一次判定之后的结果动态生成新的函数,以后就不必重新计算。

var addEvent = (function(){    if (window.addEventListener) {        return function(el, sType, fn, capture) {            el.addEventListener(sType, function(e) {                fn.call(el, e);            }, (capture));        };    } else if (window.attachEvent) {        return function(el, sType, fn, capture) {            el.attachEvent("on" + sType, function(e) {                fn.call(el, e);            });        };    }})();

这个例子,第一次 if…else… 判断之后,完成了部分计算,动态创建新的函数来处理后面传入的参数,这是一个典型的柯里化。

0 0
原创粉丝点击