柯里化函数的理解

118 阅读3分钟

一、抛出问题

我们先实现一个函数将固定个数的参数相加起来

const add = (a, b, c) => a + b + c
console.log(1,2,3) // 6

非常简单对不对,那我们再设想一下一个类似于add(1)(2)(3)实现这样的效果我们又要怎么实现?话不多说,直接上代码

1、先上简化前的

const add = (a) => {
    return (b) => {
        return (c) => {
            return a + b + c
        }
    }
}
console.log(add(1)(2)(3)) // 6

2、省略return简化后的

const add = (a) => (b) => (c) => a + b + c 
console.log(add(1)(2)(3)) // 6

二、进一步探索

1、那如果我要求实现一个函数实现以下的效果又该如何去编写呢?

console.log(add(1)(2,3)) // 6
console.log(add(1)(2)(3)) // 6
console.log(add(1,2)(3)) // 6
console.log(add(1,3)(2)) // 6
console.log(add(1,2,3)) // 6

那这样是不是有点难度的呢?那今天的重点终于来了,这涉及到了柯里化函数的概念,就是当我传入的参数小于我实现当前效果函数的参数的长度的时候,我返回一个柯里化函数,一直进行递归,直到满足我实现效果函数需传参数的长度才执行函数

// 构造一个代码来实现效果
const addfun = (a, b, c) => a + b + c
// 构造一个返回柯里化函数的参数
const current = (fn, ...args) => {
    // 通过fn.length能访问到函数参数的长度
     return (args.length >= fn.length ? 
     // 当函数实际传入的参数个数大于或等于函数参数的所需个数时我们执行函数 
     fn(...args) :
     //否则我们继续返回函数等待后续传参
     (..._args) => current(fn, ...args, ..._args)
 )
}
const add = current(addfun)

以下便是我在浏览器打印台运行的结果: image.png

三、引发思考

那到这里我们是不是已经对柯里化函数有了基本的理解了呢?那柯里化函数的作用到底是什么?

主要有3个作用: 参数复用、提前返回和 延迟执行 我们来简单的解释一下:

拿上面我们构造的add函数来讲:

    const fun = add(1)(2);
    fun(3) // 6

参数复用:拿上面 fun这个函数举例,只要传入一个参数 x,执行,计算结果就是 1 + 2 + x 的结果,1 和 2 这两个参数就直接可以复用了。

提前返回 和 延迟执行 也很好理解,因为每次调用函数时,它只接受一部分参数,并返回一个函数(提前返回),直到(延迟执行)传递所有参数为止。

四、拓展

函数固定个数传参实现不同层级的累加我们已经写出来了,那不固定个数参数且不固定层级每次都能返回结果我们又该如何实现呢?

答案就是递归+闭包+函数的toString方法

const add = (...args) => {
    let sum = args.reduce((total, item) => total + item, 0)
    const addfun = (..._args) => {
        sum = _args.reduce((total, item) => total + item, sum)
        return addfun
    }
    addfun.toString = () => {
        return sum
    }
    return addfun;
}
add(1)(2)(3) // f 6

image.png 注:返回结果不是数字类型(通过Number方法进行转换即可)