源本科技 | 码上会

JavaScript 高阶函数 map

2025/12/31
11
0

学习目标

  • 理解 map() 的核心作用:不可变转换

  • 掌握 map() 的语法、参数与返回值

  • 能够在实际开发中用于数据格式化、对象映射、字符串处理等场景

  • 区分 map()forEach()filter() 等数组方法的使用边界

  • 避免常见误区(如忽略返回值、误用于副作用操作)


什么是 map() 方法

map() 是 ES5 引入的高阶函数,用于对数组中的每个元素执行一个转换函数,并返回一个全新数组,原数组保持不变。

核心特性:

  • 不修改原数组

  • 返回新数组

  • 跳过空槽(empty slots)

  • 必须有返回值(否则对应位置为 undefined

const numbers = [1, 2, 3, 4];
const doubled = numbers.map(x => x * 2);

console.log(doubled); // [2, 4, 6, 8]
console.log(numbers); // [1, 2, 3, 4] — 原数组未变

语法与参数

const newArray = arr.map((element, index, array) => {
    // 返回新值
});

参数

类型

说明

element

任意

当前遍历的元素(必填)

index

number

当前元素的索引(可选)

array

Array

原始数组本身(可选)

示例:使用全部参数

const fruits = ['apple', 'banana', 'cherry'];

const result = fruits.map((fruit, idx, arr) => {
    return `${idx + 1}. ${fruit} (共 ${arr.length} 项)`;
});

console.log(result);
// [
//   "1. apple (共 3 项)",
//   "2. banana (共 3 项)",
//   "3. cherry (共 3 项)"
// ]

典型应用场景

1. 数值变换

// 求平方根
const squares = [1, 4, 9, 16];
const roots = squares.map(Math.sqrt);
console.log(roots); // [1, 2, 3, 4]

Math.sqrt 本身接受一个参数,可直接作为回调传入。


2. 构造新对象结构

const users = ['Alice', 'Bob', 'Charlie'];

const userObjects = users.map((name, index) => ({
    id: index + 1,
    username: name,
    isActive: true
}));

console.log(userObjects);
// [
//   { id: 1, username: "Alice", isActive: true },
//   { id: 2, username: "Bob", isActive: true },
//   ...
// ]

3. 字符串处理

const word = "Coder";

// 将字符串转为字符数组并处理
const charsWithSuffix = Array.from(word).map(char => char + '!');
// 或使用 call(如原文示例)
// const charsWithSuffix = Array.prototype.map.call(word, char => char + '!');

console.log(charsWithSuffix); // ['C!', 'o!', 'd!', 'e!', 'r!']

注意:字符串不是数组,但可通过 Array.from()call 使其兼容 map


4. 类型转换

const stringNumbers = ['10', '20', '30'];

// 转为整数
const integers = stringNumbers.map(str => parseInt(str));
console.log(integers); // [10, 20, 30]

// 更安全的方式(避免 parseInt 的进制陷阱)
const safeIntegers = stringNumbers.map(str => Number(str));

提示:parseInt('10', index)map 中可能因第二个参数(index)被误认为进制而报错,建议显式只传一个参数。


map() vs 其他数组方法

方法

是否返回新数组

是否修改原数组

主要用途

map()

✅ 是

❌ 否

转换每个元素

forEach()

❌ 否(返回 undefined

❌ 否

执行副作用(如日志、DOM 操作)

filter()

✅ 是

❌ 否

筛选符合条件的元素

reduce()

可自定义

❌ 否

聚合计算(如求和、扁平化)

错误用法示例(应避免)

// 错误:用 map 做副作用(无返回值)
arr.map(item => {
    console.log(item); // 副作用
    // 忘记 return → 新数组全是 undefined
});

// 正确:用 forEach
arr.forEach(item => console.log(item));

高级技巧

1. 链式调用

const data = [1, 2, 3, 4, 5];

const result = data
    .map(x => x * 2)
    .filter(x => x > 5)
    .map(x => `Number: ${x}`);

console.log(result); // ["Number: 6", "Number: 8", "Number: 10"]

2. 处理异步操作

注意:map 本身是同步的

// map 不等待 Promise
const urls = ['url1', 'url2'];
const promises = urls.map(url => fetch(url)); // 返回 Promise 数组

// 配合 Promise.all 使用
Promise.all(promises).then(responses => {
    // 处理所有响应
});

重点总结

要点

说明

不可变性

map() 永远返回新数组,原数组不变

必须返回值

回调函数需 return,否则新元素为 undefined

跳过空槽

[1, , 3].map(x => x * 2)[2, , 6]

适用场景

数据转换、格式化、对象映射

不要用于

纯副作用操作(应使用 forEach

性能

时间复杂度 O(n),适合中等规模数据处理


思考题

  1. 以下代码输出什么?为什么?

    const arr = [1, 2, 3];
    const newArr = arr.map(parseInt);
    console.log(newArr);
  2. 如何使用 map() 将一个用户对象数组转换为仅包含 nameemail 的新数组?