JavaScript 学习笔记:深入理解 map() 方法与面向对象特性

JavaScript 学习笔记:深入理解 map() 方法与面向对象特性

一、Array.prototype.map() 方法详解

map() 是 ES6 中引入的重要数组方法之一,属于高阶函数(Higher-order Function) 。它的核心作用是对原数组的每个元素执行一个回调函数,并返回一个由回调函数返回值组成的新数组,而不会修改原数组。

1.1 基本语法

c 复制代码
const newArray = arr.map(callbackFn(element, index, array), thisArg);
  • callbackFn:为每个元素执行的函数,必须返回一个值。

    • element:当前元素
    • index:当前索引
    • array:原数组本身
  • thisArg(可选) :指定回调函数中 this 的值

1.2 使用示例

dart 复制代码
const numbers = [1, 4, 9];
const roots = numbers.map(num => Math.sqrt(num)); // [1, 2, 3]
const doubles = numbers.map(num => num * 2);      // [2, 8, 18]

注意:map() 不会改变原数组,而是返回一个全新数组。

1.3 常见陷阱:map(parseInt) 的误区

一个经典面试题:

arduino 复制代码
console.log(["1", "2", "3"].map(parseInt)); // [1, NaN, NaN]

原因分析

map() 会传递三个参数给回调函数:(element, index, array)

parseInt(string, radix) 接收两个参数:字符串和进制基数。

因此实际调用过程如下:

javascript 复制代码
parseInt("1", 0)  // → 1(radix=0 被忽略,默认十进制)
parseInt("2", 1)  // → NaN(1进制非法)
parseInt("3", 2)  // → NaN(2进制不含数字3)

正确写法

scss 复制代码
// 方式1:显式指定基数
["1", "2", "3"].map(str => parseInt(str, 10));

// 方式2:使用 Number 构造函数(更简洁)
["1", "2", "3"].map(Number); // [1, 2, 3]

⚠️ 注意:Number() 会解析浮点数和科学计数法,而 parseInt() 只取整数部分。


二、NaN(Not a Number)详解

2.1 什么是 NaN?

  • NaN 表示"不是一个数字",但其 typeof 结果为 'number'
  • 它出现在无效的数学运算或类型转换中。

2.2 常见产生 NaN 的场景

javascript 复制代码
console.log(0 / 0);           // NaN
console.log("abc" - 1);       // NaN
console.log(undefined + 1);   // NaN
console.log(parseInt("hello")); // NaN
console.log(Math.sqrt(-1));   // NaN

2.3 NaN 的特殊性质

  • NaN 不等于任何值,包括它自己

    ini 复制代码
    console.log(NaN == NaN);     // false
    console.log(NaN === NaN);    // false
  • 正确判断 NaN 的方法

    javascript 复制代码
    if (Number.isNaN(value)) {
      console.log("这是一个 NaN");
    }

    ✅ 推荐使用 Number.isNaN(),而非全局 isNaN()(后者会进行类型转换,可能导致误判)。


三、JavaScript 的面向对象特性与包装类

3.1 JS 是完全面向对象的语言

尽管 JavaScript 有原始类型(如 string, number, boolean),但它通过包装类(Wrapper Classes) 实现了统一的对象调用风格。

例如:

perl 复制代码
"hello".length;        // 5
114.514.toFixed(2);    // "114.51"

这些看似"原始类型调用方法"的操作,在底层实际上是:

javascript 复制代码
(new String("hello")).length;
(new Number(114.514)).toFixed(2);

JS 引擎会临时创建包装对象,调用方法后立即销毁,实现"傻瓜式"编程体验。

3.2 包装类的生命周期

javascript 复制代码
let str = "hello";               // 原始字符串
let strObj = new String(str);    // 显式创建 String 对象
console.log(typeof str);         // "string"
console.log(typeof strObj);      // "object"
strObj = null;                   // 手动释放(通常不需要)

💡 日常开发中无需手动创建包装对象,JS 会自动处理。


四、字符串处理相关知识补充

4.1 字符串长度与编码

JavaScript 使用 UTF-16 编码,大多数字符占 1 个单位,但某些 Unicode 字符(如 emoji)占 2 个或更多:

arduino 复制代码
console.log("a".length);     // 1
console.log("中".length);    // 1
console.log("𝄞".length);    // 2(音乐符号)
console.log("👋".length);    // 2(emoji)

4.2 常用字符串方法对比

方法 支持负索引 参数顺序处理 示例
slice(start, end) 保持顺序,start > end 返回空 "Hello".slice(-3, -1)"ll"
substring(start, end) ❌(负数转为 0) 自动交换使 start ≤ end "Hello".substring(3, 1)"el"

4.3 查找字符位置

rust 复制代码
const str = "Hello";
console.log(str.indexOf('l'));      // 2(首次出现)
console.log(str.lastIndexOf('l'));  // 3(最后一次出现)

五、总结与最佳实践

  1. 慎用 map(parseInt) :务必显式指定进制或改用 Number
  2. 正确判断 NaN :使用 Number.isNaN() 而非 == NaN
  3. 理解包装类机制:原始类型能调用方法是 JS 的语法糖,背后是临时对象。
  4. 优先使用 map 返回新数组 :若不需要返回值,应使用 forEach
  5. 注意字符串编码问题 :处理 emoji 或生僻字时,length 可能不符合直觉。

通过深入理解 map()、NaN、包装类等核心概念,我们不仅能写出更健壮的代码,还能避免常见的"坑"。JavaScript 虽灵活,但其设计哲学强调开发者友好性与一致性,掌握这些底层机制,方能真正驾驭这门语言。

📚 参考资料:MDN - Array.prototype.map()

相关推荐
抱琴_6 分钟前
大屏性能优化终极方案:请求合并+智能缓存双剑合璧
前端·javascript
用户463989754326 分钟前
Harmony os——长时任务(Continuous Task,ArkTS)
前端
fruge6 分钟前
低版本浏览器兼容方案:IE11 适配 ES6 语法与 CSS 新特性
前端·css·es6
颜酱24 分钟前
开发工具链-构建、测试、代码质量校验常用包的比较
前端·javascript·node.js
mCell41 分钟前
[NOTE] JavaScript 中的稀疏数组、空槽和访问
javascript·面试·v8
柒儿吖1 小时前
Electron for 鸿蒙PC - Native模块Mock与降级策略
javascript·electron·harmonyos
颜酱1 小时前
package.json 配置指南
前端·javascript·node.js
todoitbo1 小时前
基于 DevUI MateChat 搭建前端编程学习智能助手:从痛点到解决方案
前端·学习·ai·状态模式·devui·matechat
oden1 小时前
SEO听不懂?看完这篇你明天就能优化网站了
前端
IT_陈寒1 小时前
React性能优化:这5个Hooks技巧让我减少了40%的重新渲染
前端·人工智能·后端