PAYATHON 2026

JavaScript 的 map() 如何使用,与 Map 有什么区别?

数据小许

先明确两者的作用

Array.prototype.map() 对数组中的元素逐一执行转换,把结果组成一个新数组。它适合已有一组数据、需要得到另一组对应数据的场景。

new Map() 创建一个保存键值关系的数据结构,适合保存、查询或更新某个键对应的值。

JavaScript 区分大小写,数组方法 map() 和构造函数 Map 是两个独立的 API。两者都涉及对应关系,使用方式和目的不同。

数组 map() 到底做了什么?

例如,把数组中的每个数乘以 2:

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

console.log(doubled); // [2, 4, 6]
console.log(numbers); // [1, 2, 3]

这里的箭头函数是传给 map() 的回调函数。map() 依次把这个数组中的元素传给它:

  • 输入 1,返回 2。
  • 输入 2,返回 4。
  • 输入 3,返回 6。

这些返回值组成新数组 [2, 4, 6],与原数组中的元素在位置和顺序上对应。

这个数组没有空槽,下面的 for 循环也能完成同样的转换:

const numbers = [1, 2, 3];
const doubled = [];

for (let i = 0; i < numbers.length; i++) {
  doubled.push(numbers[i] * 2);
}

用 map() 可以在一行中表达遍历、转换并把结果收集到新数组的过程。

回调函数可以接收什么?

回调函数可以接收三个参数:当前元素、当前索引和原数组。

const names = ["Alice", "Bob"];

const labels = names.map((name, index) => {
  return `${index + 1}. ${name}`;
});

console.log(labels); // ["1. Alice", "2. Bob"]

用不到索引和原数组时,只写第一个参数即可。回调的返回值会放在新数组的对应位置。

实际开发中什么时候使用 map()?

从对象数组中提取字段

假设有一组用户数据,需要从每个用户对象中取出对应的用户名:

const users = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" }
];

const names = users.map(user => user.name);

console.log(names); // ["Alice", "Bob"]

把数据转换成展示所需的结构

例如,将每个商品对象转换成页面展示所需的对象:

const products = [
  { id: 1, name: "键盘", price: 199 },
  { id: 2, name: "鼠标", price: 89 }
];

const items = products.map(product => ({
  id: product.id,
  label: `${product.name}:¥${product.price}`
}));

console.log(items);
// [
//   { id: 1, label: "键盘:¥199" },
//   { id: 2, label: "鼠标:¥89" }
// ]

箭头函数中的 ({ ... }) 表示直接返回一个对象字面量。

map() 和 for 循环应该怎么选?

如果需要将每个元素的转换结果组成新数组,通常可以用 map()。其他需求可以选择相应的方法或循环:

需求常用选择
把每个元素转换成一个结果map()
只保留满足条件的元素filter()
找到第一个符合条件的元素find()
逐项执行操作,不需要收集返回值forEach() 或循环
需要使用 break、continue 控制过程for 或 for...of

例如,要在找到第一个负数后停止遍历,可以使用循环:

const numbers = [3, 5, -2, 8];

for (const number of numbers) {
  if (number < 0) {
    console.log(number); // -2
    break;
  }
}

在 map() 的回调中使用 return,只会返回当前元素的转换结果,遍历不会因此终止。

选择 map() 的主要理由是它能清楚地表达数据转换的意图。它不一定比 for 更快,具体性能取决于运行环境和处理逻辑。

new Map() 有什么用途?

Map 保存键与值之间的对应关系。例如,用用户 ID 查询用户名:

const userNames = new Map();

userNames.set(101, "Alice");
userNames.set(102, "Bob");

console.log(userNames.get(101)); // "Alice"
console.log(userNames.has(102)); // true
console.log(userNames.size);     // 2

常用操作包括:

  • set(key, value):添加键值对,已有相同键时更新值。
  • get(key):取得该键对应的值。
  • has(key):检查键是否存在。
  • delete(key):删除键值对。
  • size:取得键值对数量。

键可以是字符串、数字,也可以是对象。对象作为键时,按对象身份区分;两个属性相同但分别创建的对象仍然是不同的键。

const user = { id: 101 };
const permissions = new Map();

permissions.set(user, "editor");

console.log(permissions.get(user));        // "editor"
console.log(permissions.get({ id: 101 })); // undefined

需要按 ID 查数据、缓存某个对象的计算结果,或维护一组可以增删的键值关系时,都可以考虑 Map。

为什么它们都使用 map 这个词?

“映射”表达的是一种对应关系。

数组的 map() 使用转换函数,为每个输入元素计算对应的输出。例如:

1 → 2
2 → 4
3 → 6

Map 保存键到值的对应关系:

101 → "Alice"
102 → "Bob"

数组 map() 中,不同输入可以得到相同输出,例如 [1, 3].map(() => 0) 得到 [0, 0]。Map 中,一个键只能对应一个当前值,但不同键可以对应相同的值。

两者可以配合使用:先用 map() 将用户转换成 [key, value] 数组,再构造用于查询的 Map:

const users = [
  { id: 101, name: "Alice" },
  { id: 102, name: "Bob" }
];

const usersById = new Map(
  users.map(user => [user.id, user])
);

console.log(usersById.get(102).name); // "Bob"

如果用户 ID 重复,后面的值会覆盖前面的值。

使用 map() 时容易忽略什么?

使用花括号时要显式 return

const numbers = [1, 2, 3];

const wrong = numbers.map(number => {
  number * 2;
});

console.log(wrong); // [undefined, undefined, undefined]

const correct = numbers.map(number => {
  return number * 2;
});

没有 return 时,回调返回 undefined,结果数组的对应位置也会是 undefined。

新数组不代表深拷贝

map() 自身不会修改原数组,但回调函数里的代码仍然可以修改原对象:

const users = [{ name: "Alice", active: false }];

const result = users.map(user => {
  user.active = true;
  return user;
});

console.log(users[0].active);    // true
console.log(result === users);  // false
console.log(result[0] === users[0]); // true

如果希望保留原对象,可以返回一个新对象:

const result = users.map(user => ({
  ...user,
  active: true
}));

对象展开只复制一层,嵌套对象仍可能共享引用。稀疏数组中的空槽不会触发 map() 的回调,结果数组也会保留对应的空槽。

备注:内容仅供参考。