概念:只傳遞給函數(shù)一部分參數(shù)來(lái)調(diào)用,讓它返回一個(gè)函數(shù)去處理剩下的參數(shù)
開(kāi)篇之前白对,我們先來(lái)看一個(gè)例子
function square(i) {
return i * i;
}
function double(i)
return i * 2;
}
function map(handeler, list) {
return list.map(handeler)
}
// 數(shù)組的每一項(xiàng)平方
map(square, [1, 2, 3, 4, 5]);
map(square, [6, 7, 8, 9, 10]);
// 數(shù)組的每一項(xiàng)加倍
map(dubble, [1, 2, 3, 4, 5]);
map(dubble, [6, 7, 8, 9, 10]);
例子中怔匣,創(chuàng)建了一個(gè)通知函數(shù) map,用于適應(yīng)不同的應(yīng)用場(chǎng)景。顯然亏狰,通用性不用懷疑役纹。同時(shí),例子中重復(fù)傳入了相同的處理函數(shù):square和dubble暇唾。
實(shí)際開(kāi)發(fā)中促脉,我們經(jīng)常會(huì)用到類(lèi)似的方法來(lái)實(shí)現(xiàn)我們功能上的需求。這樣寫(xiě)通用性是有了策州,但是這種通用性的增強(qiáng)必然帶來(lái)適用性的減弱瘸味。所以,我們需要在中間找到一種平衡够挂。我們更希望一種方法旁仿,用的時(shí)候只需要把參數(shù)傳進(jìn)去,不需要再傳其他的孽糖。那么枯冈,這個(gè)時(shí)候我們就需要借助curry的力量。
我們先來(lái)看一下currying簡(jiǎn)單實(shí)現(xiàn)
var add = function(x) {
return function(y) {
return x + y;
};
};
var increment = add(1);
var addTen = add(10);
increment(2);
// 3
addTen(2);
// 12
這里我們定義了一個(gè) add 函數(shù)办悟,它接受一個(gè)參數(shù)并返回一個(gè)新的函數(shù)尘奏。調(diào)用 add 之后,返回的函數(shù)就通過(guò)閉包的方式記住了 add 的第一個(gè)參數(shù)誉尖。一次性地調(diào)用它實(shí)在是有點(diǎn)繁瑣罪既,好在我們可以使用一個(gè)特殊的 curry幫助函數(shù)(helper function)使這類(lèi)函數(shù)的定義和調(diào)用更加容易。
這就是currying,到這里什么是函數(shù)柯里化相信大家已經(jīng)有一定的概念了琢感。但我們更希望的是能有一個(gè)函數(shù)幫我們把所有需要進(jìn)行柯里化的函數(shù)進(jìn)行處理丢间,而不是像上面一樣,每一個(gè)需求就按一個(gè)寫(xiě)法驹针。
currying的通用實(shí)現(xiàn)
function currying(fn) {
var slice = Array.prototype.slice,
_args = slice.call(argumengs, 1);
return function() {
var _inargs = slice.call(arguments);
return fn.apply(null, _args.concat(_inargs)
}
}
下面我們利用柯里化改造一下開(kāi)篇的第一個(gè)段代碼:
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]);
var mapDB = currying(map, dubble);
mapDB([1, 2, 3, 4, 5]);
mapDB([6, 7, 8, 9, 10]);
例子中烘挫,我們通過(guò)currying這個(gè)方法來(lái)把接受多個(gè)參數(shù)的函數(shù)變換成接受一個(gè)單一參數(shù)(最初函數(shù)的第一個(gè)參數(shù))的函數(shù)。并且返回接受余下的參數(shù)而且返回結(jié)果柬甥。這也就是我們這次要討論的主題——函數(shù) 柯里化Currying.
柯里化不僅僅是提高了代碼的合理性饮六,更重的它突出一種思想——降低適用范圍,提高適用性苛蒲。
下面我們來(lái)看一下一個(gè)范圍更廣也更為大家所熟悉的例子
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 xhr1 = new Ajax();
xhr1.get('url', {}, function(data) {
// do some thing
})
var xhr2 = new Ajax();
xhr2.post('url', {}, function(data) {
// done(data)
})
到這里卤橄,大家應(yīng)該就可以理解為什么我們可以用在用jQuery時(shí)可以用ajax.get, ajax.post這樣的方法了吧~并不是按強(qiáng)邏輯那樣重復(fù)寫(xiě)了很多不同的方法,而是利用了curry這個(gè)好幫手
后記:有些事物在你得到之前是無(wú)足輕重的臂外,得到之后就不可或缺了窟扑。微波爐是這樣,智能手機(jī)是這樣漏健,互聯(lián)網(wǎng)也是這樣——老人們?cè)跊](méi)有互聯(lián)網(wǎng)的時(shí)候過(guò)得也很充實(shí)嚎货。對(duì)我來(lái)說(shuō),函數(shù)的柯里化(curry)也是這樣蔫浆。
參考資料:JS 函數(shù)式編程指南