JavaScript 中 Array.prototype.map 的棘手用例

- Published on
- /5 mins read/---
如果你熟悉函数式编程,Array.prototype.map 一定是你每天都在使用的函数。
对我来说,map() 是一个强大的函数,但它可能有一些你不知道的棘手用例!
让我们回顾一些基础知识
map() 方法通过对调用数组的每个元素应用提供的回调函数,从调用数组创建一个新数组
简单用例
给定这个数组
let devs = [
{ id: '1', name: 'Leo', yob: 1995 },
{ id: '2', name: 'Paul', yob: 1995 },
{ id: '3', name: 'Jesse', yob: 1996 },
{ id: '4', name: 'Ken', yob: 1997 },
]
我们可以使用 map() 函数做什么:
- 从数组获取新值
let ages = devs.map((dev) => {
let currentYear = new Date().getFullYear()
return currentYear - dev.yob
})
console.log(ages) // => [25, 25, 24, 23]
- 从对象数组中提取值
let names = devs.map((dev) => dev.name)
console.log(names) // => ["Leo", "Paul", "Jesse", "Ken"]
- 在 React 应用中渲染列表
import React from 'react'
export default DeveloperProfiles = ({ devs }) => {
return (
<ul>
{devs.map((dev) => (
<li key={dev.id}>{dev.name}</li>
))}
</ul>
)
}
棘手用例
通常,我们会像这样将预定义的回调函数作为 map() 参数传递:
let extractId = (dev) => {
return dev.id
}
let ids = devs.map(extractId)
console.log(ids) // => ["1", "2", "3", "4"]
但这种习惯可能会导致接受额外参数的函数出现意外行为。
考虑这种情况 - 我们需要获取所有作为数字的 id:
// ids = ["1", "2", "3", "4"]
let idsInNumber = ids.map(parseInt)
console.log(idsInNumber) // => ???
你可能期望结果是 [1, 2, 3, 4]
,但实际结果是 [1, NaN, NaN, NaN]
我们最近在工作中遇到了这个问题,花了我一些时间才弄明白,以下是答案...
通常,我们使用带有 1 个参数(正在遍历的元素)的 map() 回调,但 Array.prototype.map 传递 3 个参数:
- 元素
- 索引
- 调用数组(我们大多数时候不使用)
而这种情况下的回调 - parseInt 通常使用 1 个参数,但它接受 2 个:
// 语法
parseInt(string [, radix])
string
:要解析的值radix
:[可选]:表示基数的整数(数学数字系统中的基数)- 通常是 10
例如:
parseInt('10') // => 10
parseInt('10', 10) // => 10
parseInt('10', 2) // => 2
parseInt('10', 4) // => 4
现在你可以看到混淆的来源了 !
map() 的第三个参数被 parseInt 忽略 - 但不是第二个!
因此,map() 的迭代步骤如下所示:
// map(parseInt) => map(parseInt(value, index))
/* 索引为 0 */ parseInt('1', 0) // => 1
/* 索引为 1 */ parseInt('2', 1) // => NaN
/* 索引为 2 */ parseInt('3', 2) // => NaN
/* 索引为 3 */ parseInt('4', 3) // => NaN
解决方案
既然你已经知道了问题的根源,解决方案就是如果你不确定你的回调如何工作,就不要将 map() 的所有参数传递给它
- 只传递你的回调需要的参数
function returnInt(element) {
return parseInt(element, 10)
}
;['1', '2', '3', '4'].map(returnInt)
// => [1, 2, 3, 4]
// 与上面相同,但使用简洁的箭头函数语法
// 如果你不需要重用回调,最好使用这种方式
;['1', '2', '3', '4'].map((numb) => parseInt(numb, 10))
// => [1, 2, 3, 4]
- 实现我们的情况的更简单方法,如 Airbnb 风格指南 所示
;['1', '2', '3', '4'].map(Number)
// => [1, 2, 3, 4]
这就是我所知道的关于 Array.prototype.map 函数的内容,欢迎在评论区分享你的用例
编码愉快!
参考资料
← Previous post何时在JavaScript中使用函数声明vs函数表达式?
Next post →拖放 API 要点