JavaScript函数柯里化

58 阅读3分钟

1、什么是函数柯里化

函数柯里化就是我们给一个函数传入一部分参数,此时就会返回一个函数来接收剩余的参数

2、简单的柯里化的实现

没有柯里化实现的案例

function sum(a,b,c){
  return a+b+c
 }
 console.log(1,2,3) //输出结果为6

将其转化为柯里化的案例

function sum(a){
  return function (b){
    return function (c){
      return a + b +c
      }
  }
}
console.log(1,2,3) //输出结果为6

简写:

const sum = a => b => c => a + b + c
console.log(1,2,3) //输出结果为6

3、函数柯里化的好处

我们希望处理函数时,希望函数功能尽可能单一。然而在实际开发中,有很多函数是多层包含并且调用的,此时用柯里化可以使需要处理的函数变得简单 如下面代码所示

 function fn(a, b, c, d) {
            return a + '://' + b + ':' + c + d
        }
        // let res = fn('http', '127.0.0.1', '80', '/a.html')
        // console.log(res)

        // let res1 = fn('http', '127.0.0.1', '443', '/b.html')
        // console.log(res1)

        // let res2 = fn('http', '127.0.0.1', '8080', '/c.html')
        // console.log(res2)


        // 外层函数 负责接接收参数
        function currying(callback, ...arg) {
            // ...arg 将后续所有实参, 以数组的形式存放在 arg 形参内, 如果没有传递的话, 是一个空数组
            // console.log(callback)    // 功能函数, 首次调用必传
            // console.log(arg)         // 基本参数, 首次调用可传可不传
            // console.log(callback.length)    // 函数名.length 能获取到函数的形参数量

            const len = callback.length

            // 内层函数负责 当前是否接受够参数了
            return function (...iArg) {
                iArg = [...arg, ...iArg]    // 开始执行共能前, 先将两次函数调用接受的参数合并为一个数组, 后续用于计算传递的参数是否足够

                if (iArg.length === len) {  // 如果传递的参数数量, 刚好是功能函数需要的数量, 代表此时参数足够, 直接执行函数即可
                    return callback(...iArg)    // 执行功能函数, 此时会得到一个拼接好的字符串, 我们将这个字符串返回出去, 就能得到功能函数的执行结果
                } else {                        // else 分支执行时表明此时函数参数仍未接受足够, 此时需要继续接受参数, 根据函数功能, 我们应该调用 currying并将之前接收的功能函数与之前传递所有的参数全部传递进去
                    return currying(callback, ...iArg)  // callback => 功能函数     ...iArg => 之前传递进来的所有的参数
                    // 这里是返回了一个 currying的调用结果, 所以相当于是返回了内层函数, 并且外层函数是接受了对应的功能函数与实际参数
                }

            }
        }


 let res = currying(fn, 'https') // 此处传递了功能函数与一个基本参数, 按照函数规则, 后续起码应该再传递够三个参数, 才能正常执行功能
let res1 = res('127.0.0.1', '80')   // 此时传递了两个参数, 加上首次调用的一个参数, 现在接收到了 3个字符串, 所以应该在传递一个参数, 才能够正常执行
let str1 = res1('/a.html')          // 此时传递了 一个 参数, 加上之前的三个字符串参数, 所以现在正好满足 4个参数, 所以现在就可能正常执行功能函数
console.log(str1)   // https://127.0.0.1:80/a.html

let res2 = currying(fn) // 此处传递了 功能函数, 没有传递基本参数, 按照函数规则, 后续起码应该传递四个参数, 才能正常执行功能
let str2 = res2('https', 'www.baidu.com', '8080', '/a.html')    // 此时传递了四个参数, 因为首次没有传递字符串, 这里就是有4个参数, 所以正常执行函数
 console.log(str2)   // https://www.baidu.com:8080/a.html

4、自动柯里化

function myCurried(fn) {
  return function curry(...args1) {
    if (args1.length >= fn.length) {
      return fn.call(null, ...args1)
    } else {
      return function (...args2) {
        return curry.apply(null, [...args1, ...args2])
      }
    }
  }
}

function sum(a, b, c, d, e) {
  return a + b + c + d + e
}
let resFunc = myCurried(sum)
console.log(resFunc(1,3,4)(1)(23))

//这里的fn.length获取的是函数传入参数的长度