切换主题
函数柯里化
为了更方便和浅显的解释何为函数柯里化,需先了解一个概念:元(variable)
。那么什么是元
呢?
在数学、物理上,
元
就是未知数的个数;在计算机科学上,元
就是函数的参数个数。
元
和函数柯里化有什么关系呢?
所谓的函数柯里化就是将一个多参数函数转换成多个单参数函数,换成
元
函数描述就是将一个n
元函数转换成n
个一元函数。
函数参数
关于函数参数,这里需要特别说明,在JavaScript
标准内置对象Function
上的length
属性 仅表示函数期望的参数数量。又由于其它函数都是由Function
派生而来(或者说是其实例,不理解的话,可以看看原型链),故所有函数都有length
这一属性。
此外,还需将其与函数内的arguments.length
区分开,两者区别如下:
Function.length
:表示函数的形参,这里的形参不包括剩余参数
,只包括在第一个具有默认值的参数之前的参数;arguments.length
:表示函数的实参。
若还是不明白两者区别,可前往
MDN
查看Function.length
与arguments.length
。
柯里化
接下来实现函数柯里化。
JavaScript
function curry(func, args) {
const len = func.length
args = args || []
return function () {
const _args = [...args, ...arguments]
if (_args.length < len) {
return curry.call(this, func, _args)
}
return func.apply(this, _args)
}
}
// 验证一下
const yui = curry((school, name, age) => {
return `${school}-${name}-${age}`
})
yui('樱丘高中', 'yui', 14) // '樱丘高中-yui-14'
yui('樱丘高中', 'yui')(14) // '樱丘高中-yui-14'
yui('樱丘高中')('yui')(14) // '樱丘高中-yui-14'
yui('樱丘高中')('yui', 14) // '樱丘高中-yui-14'
更推荐的ES6
写法
JavaScript
const curry = func =>
judge = (...args) =>
args.length === func.length
? func(...args)
: (arg) => judge(...args, arg)
// 验证同上
偏函数
偏函数是一种较特殊的柯里化函数,特殊在偏函数是固定一个或者多个参数,换成元
函数描述就是将一个n
元函数转换成一个n-x
元函数。
=> 其实Function#bind()
就是一个典型的偏函数。
JavaScript
const O = {}
function partial(func) {
const args = [].slice.call(arguments, 1)
let len = args.length
return function () {
let idx = 0
for (let i = 0; i < len; i++) {
args[i] = args[i] === O ? arguments[idx++] : args[i]
}
len = arguments.length
while (idx < len) args.push(arguments[idx++])
return func.apply(this, args)
}
}
// 验证一下
const getInfo = (school, name, age) => {
return `${school}-${name}-${age}`
}
const yui = partial(getInfo, '樱丘高中', 'yui')
yui('14') // '樱丘高中-yui-14'
const mio = partial(getInfo, '樱丘高中')
mio('mio', '15') // '樱丘高中-mio-15'
更推荐的ES6
写法
JavaScript
const partial = (func, ...args) =>
(..._args) =>
func.call(null, ...args, ..._args)
// 验证同上