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"]
但这种习惯可能会导致函数接受额外参数时出现意外行为。
考虑这种情况 - 我们需要将所有 ids 转换为数字:
// ids = ["1", "2", "3", "4"]
let idsInNumber = ids.map(parseInt)
console.log(idsInNumber) // => ???
你可能期望结果是 [1, 2, 3, 4]
,但实际结果是 [1, NaN, NaN, NaN]
😲
我们最近在 Cốc Cốc 遇到了这个问题,花了我一段时间才弄明白,这里是答案...
通常,我们使用带有 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))
/* index is 0 */ parseInt('1', 0) // => 1
/* index is 1 */ parseInt('2', 1) // => NaN
/* index is 2 */ parseInt('3', 2) // => NaN
/* index is 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 postJavaScript中何时使用函数声明vs函数表达式?
Next post →拖拽 API 要点