前端开发者进阶之函数柯里化Currying

穆乙http://www.cnblogs.com/pigtail/p/3447660.html php

在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,而且返回接受余下的参数并且返回结果的新函数的技术。这个技术由 Christopher Strachey 以逻辑学家哈斯凯尔·加里命名的,尽管它是 Moses Schönfinkel 和 Gottlob Frege 发明的。html

这是来自维基百科的名词解释。顾名思义,柯里化其实自己是固定一个能够预期的参数,并返回一个特定的函数,处理批特定的需求。这增长了函数的适用性,但同时也下降了函数的适用范围。前端

看一下通用实现:web

function currying(fn) {
            var slice = Array.prototype.slice,
            __args = slice.call(arguments, 1);
            return function () {
                var __inargs = slice.call(arguments);
                return fn.apply(null, __args.concat(__inargs));
            };
        }

柯里化的实用性体如今不少方面:数组

1 提升适用性。app

【通用函数】解决了兼容性问题,但同时也会再来,使用的不便利性,不一样的应用场景往,要传递不少参数,以达到解决特定问题的目的。有时候应用中,同一种规则可能会反复使用,这就可能会形成代码的重复性。async

看下面一个例子:函数

function square(i) {
    return i * i;
}

function dubble(i) {
    return i *= 2;
}

function map(handeler, list) {
    return list.map(handeler);
}

// 数组的每一项平方
map(square, [1, 2, 3, 4, 5]);
map(square, [6, 7, 8, 9, 10]);
map(square, [10, 20, 30, 40, 50]);
// ......

// 数组的每一项加倍
map(dubble, [1, 2, 3, 4, 5]);
map(dubble, [6, 7, 8, 9, 10]);
map(dubble, [10, 20, 30, 40, 50]);

例子中,建立了一个map通用函数,用于适应不一样的应用场景。显然,通用性不用怀疑。同时,例子中重复传入了相同的处理函数:square和dubble。post

应用中这种可能会更多。固然,通用性的加强必然带来适用性的减弱。可是,咱们依然能够在中间找到一种平衡。this

看下面,咱们利用柯里化改造一下:

function square(i) {
    return i * i;
}

function dubble(i) {
    return i *= 2;
}

function map(handeler, list) {
    return list.map(handeler);
}

var mapSQ = currying(map, square);
mapSQ([1, 2, 3, 4, 5]);
mapSQ([6, 7, 8, 9, 10]);
mapSQ([10, 20, 30, 40, 50]);
// ......

var mapDB = currying(map, dubble);
mapDB([1, 2, 3, 4, 5]);
mapDB([6, 7, 8, 9, 10]);
mapDB([10, 20, 30, 40, 50]);
// ......

咱们缩小了函数的适用范围,但同时提升函数的适性。固然,也有扩展函数适用范围的方法--反柯里化,留到下一篇再讨论。

由此,可知柯里化不单单是提升了代码的合理性,更重的它突出一种思想---下降适用范围,提升适用性。

下面再看一个例子,一个应用范围更普遍更熟悉的例子:

function Ajax() {
    this.xhr = new XMLHttpRequest();
}

Ajax.prototype.open = function(type, url, data, callback) {
    this.onload = function() {
        callback(this.xhr.responseText, this.xhr.status, this.xhr);
    }

    this.xhr.open(type, url, data.async);
    this.xhr.send(data.paras);
}

'get post'.split(' ').forEach(function(mt) {
    Ajax.prototype[mt] = currying(Ajax.prototype.open, mt);
});

var xhr = new Ajax();
xhr.get('/articles/list.php', {},
function(datas) {
    // done(datas)    
});

var xhr1 = new Ajax();
xhr1.post('/articles/add.php', {},
function(datas) {
    // done(datas)    
});

 

2 延迟执行。

 柯里化的另外一个应用场景是延迟执行。不断的柯里化,累积传入的参数,最后执行。

看下面:

var add = function() {
    var _this = this,
    _args = arguments
    return function() {
        if (!arguments.length) {
            var sum = 0;
            for (var i = 0,
            c; c = _args[i++];) sum += c
            return sum
        } else {
            Array.prototype.push.apply(_args, arguments) return arguments.callee
        }
    }
}
add(1)(2)(3)(4)();//10

通用的写法:

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;
    }
}

上面累加的例子,能够实验一下怎么写?

 

3 固定易变因素。

柯里化特性决定了它这应用场景。提早把易变因素,传参固定下来,生成一个更明确的应用函数。最典型的表明应用,是bind函数用以固定this这个易变对象。

Function.prototype.bind = function(context) {
    var _this = this,
    _args = Array.prototype.slice.call(arguments, 1);
    return function() {
        return _this.apply(context, _args.concat(Array.prototype.slice.call(arguments)))
    }
}

 

 

 

参考:

http://sombie.diandian.com/post/2013-06-28/40050585369

http://book.2cto.com/201211/9320.html

http://zh.wikipedia.org/wiki/Currying

http://www.ibm.com/developerworks/cn/web/1006_qiujt_jsfunctional/

相关文章
相关标签/搜索