Open
Description
'函数柯里化可以理解为分步接受函数的参数,等到接受完毕的时候,最终执行'。下边以实现累加为例,具体剖析:
简易版
function curry(fn){
let args=[]
return function next(...params){
if(params.length>0){ // 还有参数,则接着返回函数
args=[...args,...params];
return next
}else{ //没有参数,表明接受完所有的参数了
return fn(...args)
}
}
}
let add=curry(function(...items){
return items.reduce((prev,cur)=>{return prev+cur},0)
})
console.log(add(1)(2,3)()) //6
升级版
在简易版中,判断最终执行函数的条件是传入了空参数。有没有办法省略这一步呢。其实是有以下两个办法:
- js获取某个值的时候,会根据语境隐式调用
toString
或者valueOf
函数。 - 判断函数的参数长度;
toString
或者valueOf
方法
function curry(fn) {
let args = []
function next(...params) {
args = [...args, ...params]
return next
}
next.toString = function () {
return fn(...args)
}
next.valueOf=function(){
return fn(...args)
}
return next
}
let add = curry(function (...items) {
return items.reduce((prev, cur) => { return prev + cur }, 0)
})
//case1
let res = add(1)(2, 3)
console.log(res) //{ [Function: next] toString: [Function], valueOf: [Function] } //没有求值的操作,所以打印了函数。
// case2
let res = add(1)(2, 3)+0 //求值的操作,会调用`valueOf`。
console.log(res) //6
判断函数的参数长度
这种方法适用于预先知道需要柯里化的函数的参数个数。
function curry(fn) {
let allArgs = []
let len = fn.length
return function next(...args) {
allArgs = [...allArgs, ...args]
if (allArgs.length === len){
return fn(...allArgs)
}else{
return next
}
}
}
let add = curry(function (p1, p2, p3) {
return p1 + p2 + p3
})
console.log('res',add(1)(2,3)) //6
或者curry函数接受第二个参数,显示指定参数的个数。
function curry(fn,len) {
let allArgs = []
return function next(...args) {
allArgs = [...allArgs, ...args]
if (allArgs.length === len){
return fn(...allArgs)
}else{
return next
}
}
}
let add = curry(function (...items) {
return items.reduce((prev, cur) => { return prev + cur }, 0)
},3)
console.log('res',add(1)(2,3)) //6
补充,函数的length
上面的例子用到了函数的length属性,length表示函数预期输入的参数个数,那么给了参数默认值的,或者rest参数,都不在length中。且给了默认值后面的没有默认值的参数,也不再length中。比如:
(function(a,b,c){}).length //3 正常使用
(function(a,b,...args){}).length //2 rest参数不计入
(function(a,b,c=1){}).length //2 默认值的参数不计入
(function(a,b=2,c){}).length //1 默认值之后的参数也不计入
参考文献:
1、https://juejin.im/post/5b561426518825195f499772
2、https://es6.ruanyifeng.com/#docs/function#rest-%E5%8F%82%E6%95%B0
Metadata
Metadata
Assignees
Labels
No labels