likes
comments
collection
share

从简入繁:详解 JS 柯里化,实现 add(1, 2)(3)(4, ...)(5, ...)... 无限累加函数。

作者站长头像
站长
· 阅读数 7

什么是柯里化

  • 官方定义:把一个接收多个参数的函数,设计成一个:接收单一参数的函数,并返回一个能够接收剩余参数的新函数,最后返回结果。
  • 简单理解:调用函数A运行后返回函数B,B处理A剩余参数并返回函数C,C处理B剩余参数并返回函数D,...,最后返回结果。
// 普通函数
const add = (a, b, c) => {
    return a + b + c
}
// 柯里化函数
const curry_add = (a) => {
    return (b) => {
        return (c) => {
            return a + b + c
        }
    }
}

改造和拆解

1. 简单的递归函数

const curry_add = (a) => {
   return curry_add
}
curry_add(1)(2)(3)(4)...

简单实现无限调用,每次执行结果返回函数本身。

  • 思考:返回递归函数的同时,如何将每次执行结果的值存储在函数中?

2. 像极了闭包和记忆函数

const curry_add = (a) => {
    let num = a || 0
    const item = (b) => {
        num+= b
        console.log(num, '循环执行')
        return item
    }
    return item
}
curry_add(1)(2)(3)(4)...
# 3 "循环执行"
# 6 "循环执行"
# 10 "循环执行"

curry_add 函数被初次调用时,创建了一个拥有 num 变量item 函数 的作用域函数,在第二次和后面的执行过程中,只是一直在 累计 num调用 item 的重复工作,直到 curry_add 函数执行结束并销毁 numitem

  • 思考:如果将结果传递透出?

3. 不那么严谨的万物皆对象(简单实现)

const curry_add = (a) => {
    let num = a || 0
    const item = (b) => {
        num+= b
        item.num = num // 将 num 赋到函数上
        return item
    }
    return item
}
curry_add(1)(2)(3)(4).num
# 10

除 8 种基本类型外,万物皆为对象。所以会在 item 函数每次执行时将 num 变量赋到item.num 变量上,在 curry_add 执行结束后用 .num 调出结果。

  • 思考:如何在执行结束后返回结果而中间步骤返回函数?

4. 共生、自执行函数与隐式转换

const curry_add = (a) => {
    let num = a || 0
    const item = (b) => {
        num+= b
        return item
    }

    item.toString = () => {
        console.log('参数变化,自动触发')
        return num
    }

    return item
}
curry_add(1)(2)(3)(4)
# ƒ 10

官方说明:Object.prototype.toString() 方法返回一个表示该对象的字符串,当对象被表示为文本值时或者当以期望字符串的方式引用对象时,该方法被自动调用。

简单理解:在某个操作或者运算需要字符串而该对象又不是字符串的时候,会触发该对象的 String 转换,会将非字符串的类型尝试自动转为 String 类型。

  • 思考:如何实现 curry_add(1)(2, 3)(4)... ?

5. 展开运算符 ...

const curry_add = (...a) => {
    let num = a.reduce((t, c) => t + c, 0)

    const item = (...b) => {
        num = num + b.reduce((t, c) => t + c, 0)
        return item
    }

    item.toString = () => num

    return item
}
curry_add(1)(2, 3)(4)
# ƒ 10

初次执行用 reduce 计算结果,在递归函数中也加入 reduce 累加结果,reduce 为函数基本操作,无内容补充。

结语

在日常开发中无时无刻不遇到隐式转换的问题,例如 ===== 的问题,先转换再比较,只是我们并没有去深入了解它。所以在 js 中各种奇奇怪怪的知识点,也够我们研究好些年了,哈~

都看这儿了,点个赞再走呗~