**柯里化(Currying)**是 lambda 演算中的一个概念。
柯里化是一个函数,它一次接受一个参数,并返回一个新函数,该函数期待下一个参数。它是一种函数转换,将 f(a,b,c)
转换为可以被以 f(a)(b)(c)
的形式进行调用。
柯里化简单地说就是计算具有多个参数的函数,并将它们分解为具有单个参数的函数序列。
换句话说,柯里化是一个函数,而不是一次获取所有参数,获取第一个参数并返回一个新函数,该函数获取第二个参数并返回一个新函数,该函数获取第三个参数,以此类推,直到所有参数都完成。
柯里化之所以理想,有几个原因:
- 柯里化是一种检查方法,确保你在继续之前得到了所需的一切
- 它可以帮助您避免一次又一次地传递同一个变量(参数复用)
- 它将您的函数划分为多个较小的功能,可以处理一项职责。这使你的函数更纯粹,更不容易出错和产生副作用
- 在函数式编程中,它用于创建高阶函数
- 这可能是个人喜好,增强代码可读性
柯里化是一个接受多个参数的函数。它将把这个函数转换成一系列函数,每个小函数都接受一个参数。
一个简单累加数示例:
// 非柯里化
const add = (a, b, c) => {
return a + b + c
}
console.log(add(2, 3, 5)) // 10
// 柯里化
const addCurry = (a) => {
return (b) => {
return (c) => {
return a + b + c
}
}
}
console.log(addCurry(2)(3)(5)) // 10
以上实现柯里化更简便的方法是,利用 ES6 的箭头函数特性帮助我们编写更少的代码:
const addCurry = (a) => (b) => (c) => a + b + c
console.log(addCurry(2)(3)(5)) // 10
高级柯里化:
const curry = (fn) => {
return (curried = (...args) => {
if (fn.length !== args.length) {
return curried.bind(null, ...args)
}
return fn(...args)
})
}
const totalNum = (x, y, z) => x + y + z
const curriedTotal = curry(totalNum)
console.log(curriedTotal(10)(20)(30)) // 60
在上面的例子中,我们创建了一个需要固定数量参数的函数。
它接收一个函数 curry
作为外部函数。这个函数是一个包装函数。它返回另一个名为 curried
的函数,该函数接收带有扩展运算符 (...args)
的参数,并比较函数长度 fn.length
。
函数长度意味着无论我们在这里传递多少个参数,它都会反映在函数的 length
属性中。
但是每次参数都会增加。如果我们需要的参数数量不相等,它将返回 curried
。如果我们调用 bind
,就会创建一个新函数并传递 (...args)
。
注意:
bind
创建了一个新函数。
以下是一个简单的使用柯里化函数操作 DOM 示例:
const updateElemText = (id) => (content) => (document.querySelector(`#${id}`).textContent = content)
const updateHeaderText = updateElemText('header')
updateHeaderText('Hello D.O!')
既然你知道了柯里化的工作原理,那么柯里化和偏函数(partial application)之间有什么区别?
- 柯里化:一个接受多个参数的函数。它将把这个函数转换成一系列函数,其中每个小函数将接受一个参数,直到所有参数都完成。
- 偏函数:当给定的参数少于预期的参数时,函数将转化为偏函数,并返回一个期望剩余参数的新函数。
示例:
const addPartial = (x, y, z) => x + y + z
const partialFunc = addPartial.bind(this, 2, 3)
partialFunc(5) // 10
当函数传递的某些参数不完整时,它被称为偏函数。
柯里化和偏函数并没有真正的区别;它们是相关的,但它们有不同的理论和应用。