JavaScript 中柯里化那些你不知道的事情

155 阅读4分钟

柯里化是函数式编程中的一个过程,我们可以将具有多个参数的函数转换为一系列嵌套函数。它返回一个新函数,该函数需要下一个内联参数。 换句话说,当一个函数不是一次接受所有参数时,而是接受第一个参数并返回一个新函数,该函数接受第二个参数并返回一个新函数,该函数接受第三个参数,依此类推,直到所有参数都被履行。 也就是说,当我们把一个函数调用sum(1,2,3)变成sum(1)(2)(3) 函数接受的参数数量也称为arity

function sum(a, b) {
    // do something
}
function _sum(a, b, c) {
    // do something
}

函数sum接受两个参数(2-arity 函数)并_sum接受三个参数(3-arity 函数)。 柯里化函数是通过同时定义并立即返回它们的内部函数来链接闭包来构造的。

为什么有用?

  1. 柯里化有助于我们避免一次又一次地传递相同的变量。
  2. 它有助于创建更高阶的函数

Currying 将具有多个参数的函数转换为一个序列/一系列函数,每个函数都采用一个参数。

function sum(a, b, c) {
    return a + b + c;
}
sum(1,2,3); // 6

如我们所见,使用完整参数的函数。让我们创建一个函数的柯里化版本,看看我们如何在一系列调用中调用相同的函数(并获得相同的结果):

function sum(a) {
    return (b) => {
        return (c) => {
            return a + b + c
        }
    }
}

console.log(sum(1)(2)(3)) // 6

我们可以将这个 sum(1)(2)(3) 分开来更好地理解它:

const sum1 = sum(1);
const sum2 = sum1(2);
const result = sum2(3);
console.log(result); // 6

让我们了解一下它是如何工作的: 我们将1传递给sum函数:

let sum1 = sum(1);

它返回函数:

return (b) => {
        return (c) => {
            return a + b + c
        }
}

现在,sum1 保存上面带有参数的函数定义 b。 我们调用了这个 sum1 函数,传入 2

let sum2 = sum1(2);

sum1返回第三个函数:

return (c) => {
            return a + b + c
}

返回的函数现在存储在sum2变量中。

sum2将会:

sum2 = (c) => {
            return a + b + c
}

sum2以 3 为参数调用时,

const result = sum2(3);

它使用先前传入的参数进行计算:a = 1, b = 2 并返回 6。

console.log(result); // 6

最后一个函数只接受c变量,但将使用其他变量执行操作,这些变量的封闭函数范围早已返回。它仍然有效,因为Closure🔥

curry和部分应用🤔

有些人可能会开始认为,柯里化函数的嵌套函数数量取决于它接收的参数数量。是的,这使它成为curry。

让我们举个同样的sum例子:

function sum(a) {
    return (b, c) => {
        return a * b * c
    }
}

可以这样调用:

let x = sum(10);
x(3,12);
x(20,12);
x(20,13);

// OR

sum(10)(3,12);
sum(10)(20,12);
sum(10)(20,13);

上面的函数需要 3 个参数并具有 2 个嵌套函数,这与我们之前的版本需要 3 个参数并具有 3 个嵌套函数不同。

这个版本不是curry。 我们只是对该sum函数进行了部分应用。

Currying 和 Partial Application 是相关的(因为闭包),但它们是不同的概念。

部分应用程序将一个函数转换为另一个具有较小元数的函数。

function sum1(x, y, z) {
    return sum2(x,y,z)
}

// to

function sum1(x) {
    return (y,z) => {
        return sum2(x,y,z)
    }
}

对于 Currying,它会是这样的:

function sum1(x) {
    return (y) = > {
        return (z) = > {
            return sum2(x,y,z)
        }
    }
}

Currying根据函数的参数数量创建嵌套函数。每个函数接收一个参数。如果没有争论,就没有柯里化。

开发一个接受一个函数并返回一个柯里化函数的函数:

function currying(fn, ...args) {
    return (..._arg) => {
        return fn(...args, ..._arg);
    }
}

上面的函数接受一个我们想要柯里化的函数 (fn) 和可变数量的参数 (...args)。rest 运算符用于将 fn 之后的参数个数收集到 ...args 中。

接下来,我们返回一个函数,该函数也将其余参数收集为…_args。该函数调用原始函数 fn 通过使用扩展运算符作为参数传入 ...args 和 ..._args,然后将值返回给用户。

现在,我们可以使用上面的函数来创建 curry 函数。

function sum(a,b,c) {
    return a + b + c
}

let add = currying(sum,10);
add(20,90); // 120
add(70,60); // 140

闭包使 JavaScript 中的柯里化成为可能。我希望你学到了一些关于柯里化的新知识!

感谢阅读这篇文章♥️