从一道面试题 ['1', '2', '3'].map(parseInt) 的输出说起:理解 JS 中的类型转换与 map 方法

90 阅读3分钟

在 JavaScript 面试中,经常会遇到这样的一道题目:

['1', '2', '3'].map(parseInt); // 输出什么?

你可能会以为它等价于:

['1', '2', '3'].map(num => parseInt(num)); // [1, 2, 3]

但其实它的输出是:

[1, NaN, NaN]

为什么会这样?这背后涉及了 JavaScript 中几个关键的知识点:map 方法的行为、parseInt 函数的参数机制、以及类型转换中的 NaN

一、先看 map 方法的基本行为

Array.prototype.map 是 ES5 就引入的方法,用于对数组中的每个元素进行处理并返回一个新数组。

它的基本语法如下:

arr.map(callback(currentValue[, index[, array]])[, thisArg])
  • callback 是一个函数,接收三个参数:

    • currentValue:当前元素值
    • index(可选):当前元素索引
    • array(可选):原数组本身

我们可以通过以下方式观察 map 的执行过程:

['1','2','3'].map((num, index, arr) => {
    console.log('当前元素:', num);
    console.log('当前索引:', index);
    console.log('原数组:', arr);
    return num;
});

这段代码会打印出每个元素、索引和原数组:

当前元素: 1
当前索引: 0
原数组: ['1', '2', '3']

当前元素: 2
当前索引: 1
原数组: ['1', '2', '3']

当前元素: 3
当前索引: 2
原数组: ['1', '2', '3']

因此,在调用 ['1', '2', '3'].map(parseInt) 时,实际上是将每个元素作为第一个参数传给 parseInt,而第二个参数是索引(index)

二、再来看 parseInt 函数的参数机制

parseInt(string, radix) 接收两个参数:

  • string:要解析的字符串
  • radix(可选):进制数(2 到 36 之间)

如果省略 radix 或其值为 0,JavaScript 会根据字符串前缀来决定进制:

  • "0x" 或 "0X" 开头,按十六进制解析
  • 其他情况,默认按十进制解析

但如果提供了 radix,则严格按照该进制解析。


三、结合两者分析:为什么是 [1, NaN, NaN]

我们来手动模拟一下这个过程:

第一次循环:索引 0

parseInt('1', 0)
  • radix = 0,此时 JS 会自动判断进制。
  • '1' 不是以 '0x' 开头,所以默认按十进制解析。
  • 结果:1

✅ 正确


第二次循环:索引 1

parseInt('2', 1)
  • radix = 1,这是非法的进制数(合法范围是 2~36)
  • 因此 parseInt 忽略第二个参数,只解析第一个参数 '2'
  • 但因为 radix 不合法,整个结果返回 NaN

❌ 错误,结果为 NaN


第三次循环:索引 2

parseInt('3', 2)
  • 进制是 2(二进制),尝试将 '3' 解析为二进制数字
  • 但在二进制中,只能有 0 和 13 是无效字符
  • 所以返回 NaN

❌ 错误,结果为 NaN

📌 什么是 NaN

在 JavaScript 中,NaN 表示“不是数字”(Not-a-Number),但它有一个奇怪的特点:

typeof NaN; // "number"

也就是说,虽然它是“不是数字”,但它的类型却是 "number"。 判断是否为 NaN 的正确方法是使用:

isNaN(value); // 不推荐,容易出错
Number.isNaN(value); // 推荐,ES6 新增

四、如何正确使用 map + parseInt?

如果你想把字符串数组转成数字数组,应该写成:

['1', '2', '3'].map(Number); // [1, 2, 3]

或者:

['1', '2', '3'].map(str => parseInt(str)); // [1, 2, 3]

如果你一定要用 parseInt 并确保进制是 10:

['1', '2', '3'].map(str => parseInt(str, 10)); // [1, 2, 3]

结语

这道看似简单的题目,实际上考察了多个 JS 基础知识,包括:

  • 高阶函数的理解(如 map
  • 类型转换(字符串 → 数字)
  • 参数传递机制(parseInt 的第二个参数)
  • 对 NaN 的理解

对于前端开发者来说,掌握这些细节不仅有助于通过面试,也能写出更健壮、可靠的代码。