JavaScript 中的 Map、Filter 和 Reduce
本文是对 JavaScript 的 map、filter 和 reduce 方法的基本介绍,并提供了 JavaScript 函数式编程的实际应用案例。
它们有什么共同点?
- 这三个函数都是数组方法(即可以对数组变量调用的方法)。
- 每个函数返回的值都是一个新数组,其中包含对您提供的函数中原始数组执行的操作的结果。
地图
- 该
map()方法允许您遍历数组中的每个元素,然后通过使用提供的函数以任何所需的方式操作每个元素。 - 提供的函数可以是匿名函数,也可以是命名函数。
- 需要特别注意的是,只有当您期望函数返回值时才应使用此方法。否则,如果您想修改原始数组,
map()建议使用 JavaScript 的 ` get` 方法。forEach() - TL;DR -
map()是一个for带有返回值的循环。
基本示例
- 这是MDN网页上提供的关于该
map()方法的一个简单示例。
const evenNumbers = [2, 4, 6]
const result = evenNumbers.map(currentValue => currentValue * 2)
// result = [4, 8, 12]
实际应用案例
- 这是你经常会遇到的情况:API 调用返回一个包含用户信息的对象数组。
- 此处的目的是从 API 收到的响应中提取名称列表。
const users = [
{
'name': 'John Doe',
'address': 'Wellington St, Ottawa, ON K1A 0A9'
},
{
'name': 'Jane Doe',
'address': '1600 Pennsylvania Ave NW, Washington, DC 20500'
},
{
'name': 'Hannibal Lecter',
address: '10800 97 Ave NW, Edmonton, AB T5K 2B6'
}]
const names = users.map(currentItem => {
return currentItem['name']
})
// names = ['John Doe', 'Jane Doe', 'Hannibal Lecter']
筛选
- 与该方法类似
map(),该filter()方法允许您遍历数组的元素。 - 不过,此案例的不同之处在于,它
filter()返回的值能够通过所提供的某些测试用例。
基本示例
- 这是MDN网页上提供的另一个关于该
filter()方法的简单示例。
const numbers = [2, 4, 6, 11, 12, 33]
const evenNumbers = numbers.filter(x => x % 2 === 0)
// evenNumbers = [2, 4, 6, 12]
实际应用案例
- 与前面的例子类似,这种情况是指 API 调用返回一个包含用户信息的对象。
- 目标是从 API 返回的响应中提取居住在美国境外的用户的姓名。
- 目标是从 API 返回的响应中提取居住在美国境外的用户的姓名。
const users = [
{
'name': 'John Doe',
'address': 'Wellington St, Ottawa, ON K1A 0A9',
'country': 'Canada'
},
{
'name': 'Jane Doe',
'address': '1600 Pennsylvania Ave NW, Washington, DC 20500',
'country': 'United States'
},
{
'name': 'Hannibal Lecter',
'address': '10800 97 Ave NW, Edmonton, AB T5K 2B6',
'country': 'Canada'
}]
const expatriates = users.filter(currentItem => {
return currentItem['country'] !== 'United States'
})
/* expatriates = [
{
name: 'John Doe',
address: 'Wellington St, Ottawa, ON K1A 0A9',
country: 'Canada'
},
{
name: 'Hannibal Lecter',
address: '10800 97 Ave NW, Edmonton, AB T5K 2B6',
country: 'Canada'
}]
*/
- 如果我们想要获取一个只包含名称的数组,那么仅使用此代码片段是不够的。
- 因此,基于我们之前对该
map()方法的了解,我们需要再调用一次函数。
const expatriateNames = expatriates.map(currentValue => {
return currentValue['name']
})
// expatriateNames = ['John Doe', 'Hannibal Lecter']
减少
- 顾名思义,该
reduce()方法接受一个包含多个值的数组,并将它们“简化”为一个单一的返回值。
句法
array.reduce((accumulator, current) => {}, initialValue)
基本示例
- 在这个例子中,我们试图遍历数组的元素并将它们相加。
const array = [1, 2, 3]
const result = array.reduce((previousValue, currentValue) => {
return previousValue + currentValue
})
// result = 6
实际应用案例
- 之前提供的实际用例
filter()并不理想,因为我们不得不依赖两个不同的函数调用才能获得想要的结果。 - 在这个实现中,我们的目标与之前相同,即从 API 收到的响应中提取居住在美国境外的用户的姓名列表。
- 在这种情况下,我们可以将两个
filter()方法map()调用合并为一个函数reduce()。
const users = [
{
'name': 'John Doe',
'address': 'Wellington St, Ottawa, ON K1A 0A9',
'country': 'Canada'
},
{
'name': 'Jane Doe',
'address': '1600 Pennsylvania Ave NW, Washington, DC 20500',
'country': 'United States'
},
{
'name': 'Hannibal Lecter',
'address': '10800 97 Ave NW, Edmonton, AB T5K 2B6',
'country': 'Canada'
}]
const expatriates = users.reduce((result, user) => {
// filter() equivalent
if (user['country'] === 'United States') {
return result
}
// map() equivalent
result.push(user['name'])
return result
}, initialValue = [])
- 在此实现中,我们不向累加器数组添加任何值,在本例中我们将其称为
result,从而成功地过滤掉居住在美国境外的用户。 - 接下来,一旦我们通过了初始
if语句检查,我们就将用户名添加到accumulator数组中。 - 需要注意的是,虽然 reduce 函数可以返回单个输出,但通过将初始值初始化为空数组,该返回值也可以是一个数组。
- 也许,我最喜欢的解释是
reduce()将 视为accumulator前一个值。
鸣谢
- 如果没有这些优秀的工具和内容创作者,这篇文章就不可能完成。