一泛鸟、簡介
維基百科中的定義:柯里化(Currying)奄容,又稱部分求值,是把接受多個參數(shù)的函數(shù)變換成接受一個單一參數(shù)(最初函數(shù)的第一個參數(shù))的函數(shù)啡邑,并且返回接受余下的參數(shù)而且返回結(jié)果的新函數(shù)的技術(shù)贱勃。這個技術(shù)以邏輯學(xué)家哈斯凱爾·加里命名的。
柯里化是函數(shù)式語言都有的一個特性,如Perl募寨,Python族展,JavaScript。這里介紹JavaScript中柯里化的思想及應(yīng)用拔鹰。
二、柯里化代碼分析
// 簡單的柯里化例子
// 原函數(shù)
function add(a, b, c) {
return a + b + c;
}
// 將原函數(shù)柯里化
function _add(a) {
return function(b) {
return function(c) {
return a + b + c;
}
}
}
// 將add函數(shù)柯里化后贵涵,以下2種調(diào)用方式是等價的
add(1, 2, 3);
_add(1)(2)(3);
我們靠眼力自己封裝的柯里化函數(shù)自由度偏低列肢,
下面來看一個比較通用的柯里化例子(函數(shù)為固定參數(shù)個數(shù)的柯里化)
// 通用的柯里化例子
// 原函數(shù)
function add(a, b, c) {// 函數(shù)可處理的參數(shù)個數(shù)為3
return a + b + c;
}
// 通用的柯里化函數(shù)
function createCurry(func, args) {
// 獲取被柯里化的函數(shù)的參數(shù)個數(shù),即func實(shí)際可以處理的參數(shù)個數(shù)宾茂,這里是3
var arity = func.length;
// 用來存儲柯里化時需要被復(fù)用的參數(shù)
var args = args || [];
return function() {
// [].slice.call(arguments)等價于arguments.slice
// [].slice.call(arguments)的作用是將argments這個類數(shù)組對象轉(zhuǎn)為數(shù)組
var _args = [].slice.call(arguments);
// [].push.apply(_args, args)等價于_args.push(args)
[].push.apply(_args, args);
// 如果參數(shù)個數(shù)小于最初的func.length瓷马,則遞歸調(diào)用,繼續(xù)收集參數(shù)
if (_args.length < arity) {
return createCurry.call(this, func, _args);
}
// 參數(shù)收集完畢跨晴,則執(zhí)行func
return func.apply(this, _args);
}
}
// 將原函數(shù)柯里化
var _add = createCurry(add)
// 將add函數(shù)柯里化后欧聘,以下4種調(diào)用方式是等價的
1、add(1,2,3)
2端盆、_add(1,2,3)
3怀骤、_add(1)(2)(3)
4、_add(1,2)(3)
在lodash.js中的也有_.curry()函數(shù)焕妙。
三蒋伦、柯里化使用場景
- 參數(shù)復(fù)用。固定不變的參數(shù)焚鹊,實(shí)現(xiàn)參數(shù)復(fù)用是 Currying 的主要用途之一痕届。上例中調(diào)用方式改為 _add=createCurry(add,10),則實(shí)現(xiàn)復(fù)用參數(shù)10,實(shí)現(xiàn)每次調(diào)用_add函數(shù)都加10的功能末患。
- 提高適用性研叫。可點(diǎn)擊查看本鏈接中的例子
- 延遲執(zhí)行/計算。延遲計算:一個currying的函數(shù)首先會接受一些參數(shù)璧针,接受了這些參數(shù)后嚷炉,該函數(shù)并不會立即求值,而是繼續(xù)返回另外一個函數(shù)陈莽,剛才傳入的參數(shù)在函數(shù)形成的閉包里被保存起來渤昌。待到函數(shù)真正需要求值的時候,之前傳入的參數(shù)都會被一次性用于求值走搁。 上面的例子可以比較好的說明了独柑,收集所有參數(shù),收集完才進(jìn)行最后的加法運(yùn)行私植。
四忌栅、注意
在柯里化的實(shí)現(xiàn)中,我們知道柯里化雖然具有了更多的自由度,但同時柯里化通用式里調(diào)用了arguments對象索绪,使用了遞歸與閉包湖员,因此柯里化的自由度是以犧牲了一定的性能為代價換來的。只有在情況變得復(fù)雜時瑞驱,才是柯里化大顯身手的時候娘摔。
如果我們只是想提前綁定參數(shù),那么我們有很多好幾個現(xiàn)成的選擇唤反,bind凳寺,箭頭函數(shù)等,而且性能比Curring更好彤侍。
Currying 生于函數(shù)式編程肠缨,也服務(wù)于函數(shù)式編程。假如沒有準(zhǔn)備好寫純正的函數(shù)式代碼盏阶,那么 Currying 有更好的替代品晒奕。
相關(guān)參考
柯里化
JS中的柯里化
前端開發(fā)者進(jìn)階之函數(shù)柯里化Currying
大佬,JavaScript 柯里化名斟,了解一下脑慧?