Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

函数柯里化 #26

Open
keep-run opened this issue Jul 5, 2020 · 0 comments
Open

函数柯里化 #26

keep-run opened this issue Jul 5, 2020 · 0 comments

Comments

@keep-run
Copy link
Owner

keep-run commented Jul 5, 2020

'函数柯里化可以理解为分步接受函数的参数,等到接受完毕的时候,最终执行'。下边以实现累加为例,具体剖析:

简易版

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant