簡樸來說,柯里函數就是只接收一個參數的函數,柯里化的劈頭請參看這篇文章:函數式編程入門教程
一般來說,假如三個數乞降的函數我們會如許寫:
function _sum3(x, y, z) {
return x + y + z
}
假如只斟酌完成這個函數的柯里化,我們能夠如許做:
function sum3(x) {
return function(y) {
return function(z) {
return x + y + z
}
}
}
console.log(sum3(1)(2)(3)) // 6
視察上面兩種差別的寫法能夠發明,第二種寫法實在就是首先把三個參數網絡起來,然後到末了再挪用第一種寫法的函數:
function sum3(x) {
return function(y) {
return function(z) {
return _sum3(x, y, z)
}
}
}
console.log(sum3(1)(2)(3)) // 6
所以柯里化的寫法只是把經常運用寫法包裝了一下,能夠運用一個專用的柯里化函數完成這類包裝。柯里化函數是一種高階函數,我們把它命名為curry
function curry(fn) {
return function(y) {
return function(z) {
return fn(x, y, z)
}
}
}
var sum3 = curry((x, y, z) => {
return x + y + z
})
console.log(sum3(1)(2)(3)) // 6
假如有要寫一種越發通用的,能夠柯里化具有恣意多個參數的函數呢,比方sumN(1)(2)(3)…(N),根據之前的寫法,大概是這個模樣的:
function curryN(fn) {
return function(a1) {
return function(a2) {
return function(a3) {
//......
return function(aN) {
return fn(a1, a2, a3, ...aN)
}
}
}
}
}
很輕易想到能夠用一個遞歸函數來簡化這類寫法,將上面那些看起來類似的函數構造命名為nest,就能夠寫為:
function nest(fn) {
return function(x) {
return nest(fn)
}
}
function curry(fn) {
nest(fn)
}
這裏缺乏一個輪迴停止的推斷,所以nest函數先引入一個新參數i,當i === N時遞歸停止
function nest(fn, i) {
return function(x) {
if (i === N) {
return fn(...)
}
return nest(fn, i + 1)
}
}
function curry(fn) {
return nest(fn, 1)
}
接着,須要一個寄存恣意多個參數的數組,將這個數組命名為args,然後傳入nest函數
function nest(fn, i, args) {
return function(x) {
args.push(x)
if (i === fn.length) {
return fn(...args)
}
return nest(fn, i + 1, args)
}
}
function curry(fn) {
const args = []
return nest(fn, 1, args)
}
末了在增加一個處置懲罰0個參數的狀況,我們就完成了最終版的柯里化函數
function curry(fn) {
if (fn.length === 0) {
return fn
}
const args = []
return nest(fn, 1, args)
}
測試一下,在線demo:
const log1 = curry((x) => console.log(x))
log1(10) // 10
const mul3 = curry((x, y, z) => console.log(x*y*z))
mul3(2)(3)(4) // 24