"小爷我是看文档学习的。" ------ 这句话道出了真正成长的起点。本文将结合 MDN 官方文档、底层原理、常见陷阱与高频面试题,系统梳理
Array.prototype.map、原始类型包装类、特殊数值(NaN/Infinity)以及字符串操作细节,助你构建扎实的 JavaScript 核心知识体系。
一、map 方法:函数式编程的基石
1.1 基础定义(源自 ES5,ES6 广泛应用)
map() 是数组的高阶函数 ,用于对每个元素执行一次回调函数,并返回一个全新数组,原数组不变。
c
javascript
编辑
const doubled = [1, 2, 3].map(x => x * 2); // [2, 4, 6]
- ✅ 不修改原数组(immutable)
- ✅ 返回新数组,长度与原数组一致
- ✅ 回调函数接收三个参数:
(element, index, array)
1.2 经典陷阱:[1, 2, 3].map(parseInt) 为何输出 [1, NaN, NaN]?
这是大厂高频面试题!
错误直觉:
scss
javascript
编辑
["1", "2", "3"].map(parseInt) // 期望 [1, 2, 3]
实际执行逻辑:
map 传参为 (element, index, array),而 parseInt(string, radix) 第二个参数是进制!
| 调用 | 等价于 | 结果 |
|---|---|---|
parseInt("1", 0) |
radix=0 → 默认十进制 | 1 |
parseInt("2", 1) |
radix=1(非法) | NaN |
parseInt("3", 2) |
二进制中无 "3" | NaN |
✅ 正确写法:
javascript
javascript
编辑
arr.map(x => parseInt(x, 10)); // 显式指定十进制
// 或更简洁:
arr.map(Number); // 适用于纯数字字符串
💡 面试加分点:指出
Number()与parseInt()区别------前者支持浮点和科学计数法,后者只取整。
二、JavaScript 的"面向对象"幻觉:原始类型包装类
2.1 为什么 "hello".length 能用?
在传统语言(如 Java)中,原始类型(primitive)不能调用方法。但 JS 为了简化开发者体验 ,引入了自动包装机制。
当你写:
matlab
javascript
编辑
"hello".length
JS 引擎内部会临时执行:
javascript
javascript
编辑
(new String("hello")).length
然后立即销毁这个临时对象。
2.2 包装类有哪些?
| 原始类型 | 包装类 |
|---|---|
| string | String |
| number | Number |
| boolean | Boolean |
| symbol | Symbol(不可构造) |
| bigint | BigInt(不可构造) |
⚠️ 注意:
null和undefined没有包装类!
2.3 验证包装行为
javascript
javascript
编辑
let str = "hello"; // 原始类型
console.log(typeof str); // "string"
let obj = new String("hello"); // 对象类型
console.log(typeof obj); // "object"
// 但两者 .length 行为一致
console.log(str.length); // 5
console.log(obj.length); // 5
📌 面试提示:不要手动使用
new String(),它会产生不必要的对象开销,且==比较可能出错。
三、特殊数值:NaN vs Infinity
3.1 本质区别
| 特性 | NaN |
Infinity |
|---|---|---|
| 含义 | Not a Number(无效计算) | 无穷大(有效但超出范围) |
| 类型 | "number" |
"number" |
| 自反性 | NaN !== NaN |
Infinity === Infinity |
| 产生场景 | 0/0, Math.sqrt(-1), "abc" - 1 |
1/0, Number.MAX_VALUE * 2 |
3.2 如何正确判断?
javascript
javascript
编辑
// 判断 NaN
Number.isNaN(NaN); // true(推荐)
isNaN("abc"); // true(危险!会类型转换)
// 判断 Infinity
x === Infinity; // true
isFinite(Infinity); // false(NaN 和 Infinity 都返回 false)
3.3 大厂面试题模板
Q:
typeof NaN是什么?如何判断一个值是NaN?A:
typeof NaN返回"number",这是 JS 的历史设计。- 正确判断应使用
Number.isNaN(value),因为它不会进行类型转换,只对真正的NaN返回true。- 避免使用全局
isNaN(),因为它会先尝试将参数转为数字,导致"abc"也被误判为NaN。
四、字符串操作细节:易错 API 对比
4.1 slice(start, end) vs substring(start, end)
| 特性 | slice() |
substring() |
|---|---|---|
| 负数索引 | ✅ 支持(-1 表示末尾) |
❌ 转为 0 |
| 参数顺序 | start > end → 返回空串 |
自动交换参数 |
| 推荐度 | ✅ 高(行为可预测) | ⚠️ 低 |
vbscript
javascript
编辑
"hello".slice(-3, -1); // "ll"
"hello".substring(-3, -1); // ""(因为 -3 → 0, -1 → 0)
"hello".slice(3, 1); // ""
"hello".substring(3, 1); // "el"(自动变为 substring(1, 3))
4.2 str[i] vs str.charAt(i)
| 特性 | str[i] |
str.charAt(i) |
|---|---|---|
| 越界返回 | undefined |
空字符串 "" |
| 兼容性 | ES5+ | 所有浏览器 |
| 性能 | 略快 | 略慢 |
perl
javascript
编辑
"hi"[10]; // undefined
"hi".charAt(10); // ""
💡 实践建议:现代开发优先用
str[i],除非需要兼容 IE8 以下。
4.3 字符串长度与 Unicode
JS 使用 UTF-16 编码,因此:
- 英文、中文:1 个字符 = 1 个 code unit →
.length = 1 - Emoji、生僻字:1 个字符 = 2 个 code units →
.length = 2
arduino
javascript
编辑
"a".length; // 1
"中".length; // 1
"😂".length; // 2(代理对)
🔍 深层知识:若需准确计算"用户可见字符数",应使用
Array.from(str).length或Intl.Segmenter(新 API)。
五、其他数组 API 小知识
5.1 map vs forEach
| 方法 | 返回值 | 用途 |
|---|---|---|
map |
新数组 | 数据转换(必须 return) |
forEach |
undefined |
执行副作用(如 console.log) |
❌ 错误用法:不用
map返回值 → 应改用forEach。
5.2 稀疏数组处理
map 不会遍历空槽(empty slots) ,结果数组仍保持稀疏:
ini
javascript
编辑
[1, , 3].map(x => x * 2); // [2, empty, 6]
5.3 通用性(Generic)
map 可通过 call 用于类数组对象:
ini
javascript
编辑
const arrayLike = { 0: 'a', 1: 'b', length: 2 };
Array.prototype.map.call(arrayLike, x => x.toUpperCase()); // ['A', 'B']
六、总结:构建你的知识网络
| 主题 | 核心要点 |
|---|---|
map |
返回新数组、不改变原数组、注意回调参数陷阱 |
| 包装类 | 原始类型临时转对象、不要手动 new String |
NaN/Infinity |
都是 number 类型、判断用 Number.isNaN、x === Infinity |
| 字符串 API | slice > substring、[] > charAt、注意 Unicode 长度 |
| 面向对象 | JS 是"基于对象"的语言,通过包装类实现原始类型方法调用 |
🌟 终极建议:
- 遇到问题先查 MDN 文档(到时候面试官问你,你就说你是看文档的选手,文档教的)
- 多写测试代码验证猜想
- 面试时不仅要答"是什么",更要讲清"为什么"和"怎么用"
附:高频面试题清单
[1, 2, 3].map(parseInt)为什么不是[1, 2, 3]?typeof NaN是什么?如何安全判断NaN?"hello".length背后发生了什么?slice和substring有什么区别?- 为什么
NaN !== NaN?如何利用这一点检测NaN?
掌握这些,你离大厂 offer 又近了一步!🚀