如何在 JavaScript 中使用 Currying 的实用示例
很多时候,我看到一些关于 X 语言概念的解释,虽然我明白它们的作用,但还是会想“我到底能用在哪儿?”。
又或者,有些例子过于理论化,让你很难理解在日常编程中应该如何运用。
我过去发现的一个令人困惑的概念是柯里化。
如果您不知道 Currying 是什么,它本质上是一种编程技术,即采用具有多个参数的函数,然后将其转换为较小的顺序函数,每次传递一个参数。
您可能会看到一些类似这样的示例:
// your normal function
const add = (a, b) => {
return a + b;
}
console.log(add(1,2)); // 3
// using currying
const add = (a) => {
return (b) => {
return a + b;
}
}
console.log(add(1)(2)); // 3
如果您和我一样,您可能会想“我到底为什么要使用第二种情况?”。
答案是,你不应该这么做。
但这并不是因为柯里化毫无意义,而只是因为我认为这个例子不太实用。
何时应该使用柯里化
现在,假设我们有一个对象数组,如下所示:
const list = [
{
id: 1,
name: 'Steve',
email: 'steve@example.com',
},
{
id: 2,
name: 'John',
email: 'john@example.com',
},
{
id: 3,
name: 'Pamela',
email: 'pam@example.com',
},
{
id: 4,
name: 'Liz',
email: 'liz@example.com',
},
];
并且,如果某个对象的某个属性与某个值匹配,则需要将其移除。例如,如果对象的 name 属性等于“John”,则需要将其过滤掉。
最简单的方法是这样做:
const noJohn = list.filter(item => item.name !== 'John');
console.log(noJohn);
/**
[
{ id: 1, name: 'Steve', email: 'steve@example.com' },
{ id: 3, name: 'Pamela', email: 'pam@example.com' },
{ id: 4, name: 'Liz', email: 'liz@example.com' }
]
*/
这样可以实现,但无法复用,因为你硬编码了想要移除的名称。
更好的方法是将其包装成一个函数,并将名称作为参数传递:
const filterByName = (list, name) => {
return list.filter(item => item.name !== name);
}
console.log(filterByName(list, 'John'));
/**
[
{ id: 1, name: 'Steve', email: 'steve@example.com' },
{ id: 3, name: 'Pamela', email: 'pam@example.com' },
{ id: 4, name: 'Liz', email: 'liz@example.com' }
]
*
现在,假设您要在同一段代码中的两个或多个地方使用相同的过滤函数,或者您想保持代码简洁,并将过滤函数单独放在一个变量中。您可以尝试这样做:
const filtering = item => item.name !== name;
const filterByName = (list, name) => {
return list.filter(filtering);
}
但是上述操作会抛出一个错误,因为filtering
根本不知道name
是什么。
这就是柯里化发挥作用的地方!
因此您需要将上面的代码更改为:
// we add another function on top of the previous
const filtering = (name) => (item) => item.name !== name;
const filterByName = (list, name) => {
return list.filter(filtering(name));
}
console.log(filterByName(list, 'John'));
/**
[
{ id: 1, name: 'Steve', email: 'steve@example.com' },
{ id: 3, name: 'Pamela', email: 'pam@example.com' },
{ id: 4, name: 'Liz', email: 'liz@example.com' }
]
*
那么发生了什么?该filtering
函数有一个顶层函数,它接受name
as 输入,然后返回一个接受 as 参数的新函数item
。
然后filter
函数将运行的结果filtering(name)
,这是一个函数,它将传递该项目。
如果我们使用老式的函数语法,对于像我这样的老前辈来说,它会被翻译成这样:
function filterByName(list, name) {
return list.filter(function(nameToFilter) {
// nameToFilter is declared at this point
return function(item) {
// item is declared here
return item.name !== nameToFilter;
}
}(name));
}
我希望这可以更好地解释一下 JavaScript 中柯里化是如何工作的。
文章来源:https://dev.to/darkmavis1980/a-practical-example-on-how-to-use-currying-in-javascript-1ae9