如何在 JavaScript 中使用 Currying 的实用示例

2025-05-24

如何在 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
Enter fullscreen mode Exit fullscreen mode

如果您和我一样,您可能会想“我到底为什么要使用第二种情况?”。

答案是,你不应该这么做。

但这并不是因为柯里化毫无意义,而只是因为我认为这个例子不太实用。

何时应该使用柯里化

现在,假设我们有一个对象数组,如下所示:

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',
  },
];
Enter fullscreen mode Exit fullscreen mode

并且,如果某个对象的某个属性与某个值匹配,则需要将其移除。例如,如果对象的 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' }
]
*/
Enter fullscreen mode Exit fullscreen mode

这样可以实现,但无法复用,因为你硬编码了想要移除的名称。
更好的方法是将其包装成一个函数,并将名称作为参数传递:

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' }
]
*
Enter fullscreen mode Exit fullscreen mode

现在,假设您要在同一段代码中的两个或多个地方使用相同的过滤函数,或者您想保持代码简洁,并将过滤函数单独放在一个变量中。您可以尝试这样做:

const filtering = item => item.name !== name;

const filterByName = (list, name) => {
  return list.filter(filtering);
}
Enter fullscreen mode Exit fullscreen mode

但是上述操作会抛出一个错误,因为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' }
]
*
Enter fullscreen mode Exit fullscreen mode

那么发生了什么?该filtering函数有一个顶层函数,它接受nameas 输入,然后返回一个接受 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));
}
Enter fullscreen mode Exit fullscreen mode

我希望这可以更好地解释一下 JavaScript 中柯里化是如何工作的。

文章来源:https://dev.to/darkmavis1980/a-practical-example-on-how-to-use-currying-in-javascript-1ae9
PREV
自由职业前期实用指南
NEXT
史上最受推荐的 25 本创业书籍 史上最受推荐的 25 本创业书籍。