Array.prototype.map()

基线 广泛可用

此功能已成熟稳定,并在许多设备和浏览器版本中正常运行。它自 2015 年 7 月.

报告反馈

尝试一下

语法

map() 方法用于 Array 实例,它创建一个新的数组,该数组填充了对调用数组中每个元素调用提供的函数的结果。
map(callbackFn)
map(callbackFn, thisArg)

js

在执行 callbackFn 时用作 this 的值。参见 迭代方法

返回值

描述

一个新数组,其中每个元素都是回调函数的结果。

map() 方法是一个 迭代方法。它对数组中的每个元素调用一次提供的 callbackFn 函数,并根据结果构建一个新数组。阅读 迭代方法 部分,了解有关这些方法如何普遍工作的信息。

callbackFn 仅针对已分配值的数组索引调用。它不会针对 稀疏数组 中的空槽调用。

map() 方法是 泛型的。它只期望 this 值具有 length 属性和整型键属性。

示例

由于 map 构建了一个新数组,因此在不使用返回的数组的情况下调用它是一种反模式;请改用 forEachfor...of

将数字数组映射到平方根数组

map() 方法用于 Array 实例,它创建一个新的数组,该数组填充了对调用数组中每个元素调用提供的函数的结果。
const numbers = [1, 4, 9];
const roots = numbers.map((num) => Math.sqrt(num));

// roots is now     [1, 2, 3]
// numbers is still [1, 4, 9]

以下代码获取一个数字数组,并创建一个包含第一个数组中数字平方根的新数组。

使用 map 重新格式化数组中的对象

map() 方法用于 Array 实例,它创建一个新的数组,该数组填充了对调用数组中每个元素调用提供的函数的结果。
const kvArray = [
  { key: 1, value: 10 },
  { key: 2, value: 20 },
  { key: 3, value: 30 },
];

const reformattedArray = kvArray.map(({ key, value }) => ({ [key]: value }));

console.log(reformattedArray); // [{ 1: 10 }, { 2: 20 }, { 3: 30 }]
console.log(kvArray);
// [
//   { key: 1, value: 10 },
//   { key: 2, value: 20 },
//   { key: 3, value: 30 }
// ]

以下代码获取一个对象数组,并创建一个包含重新格式化的新对象的数组。

使用 parseInt() 与 map()

map() 方法用于 Array 实例,它创建一个新的数组,该数组填充了对调用数组中每个元素调用提供的函数的结果。
["1", "2", "3"].map(parseInt);

通常使用带有一个参数(正在遍历的元素)的回调函数。某些函数通常也只带有一个参数使用,即使它们接受其他可选参数。这些习惯可能导致令人困惑的行为。请考虑

虽然可能预期结果为 [1, 2, 3],但实际结果是 [1, NaN, NaN]

parseInt 通常使用一个参数,但它接受两个参数。第一个是表达式,第二个是基数,而回调函数 Array.prototype.map 传递 3 个参数:元素、索引和数组。第三个参数被 parseInt 忽略,但不是第二个参数!这是潜在混淆的根源。

map() 方法用于 Array 实例,它创建一个新的数组,该数组填充了对调用数组中每个元素调用提供的函数的结果。
/* first iteration  (index is 0): */ parseInt("1", 0); // 1
/* second iteration (index is 1): */ parseInt("2", 1); // NaN
/* third iteration  (index is 2): */ parseInt("3", 2); // NaN

以下是迭代步骤的简要示例

map() 方法用于 Array 实例,它创建一个新的数组,该数组填充了对调用数组中每个元素调用提供的函数的结果。
["1", "2", "3"].map((str) => parseInt(str, 10)); // [1, 2, 3]

要解决这个问题,请定义另一个只接受一个参数的函数

map() 方法用于 Array 实例,它创建一个新的数组,该数组填充了对调用数组中每个元素调用提供的函数的结果。
["1", "2", "3"].map(Number); // [1, 2, 3]

// But unlike parseInt(), Number() will also return a float or (resolved) exponential notation:
["1.1", "2.2e2", "3e300"].map(Number); // [1.1, 220, 3e+300]

// For comparison, if we use parseInt() on the array above:
["1.1", "2.2e2", "3e300"].map((str) => parseInt(str, 10)); // [1, 2, 3]

你也可以使用 Number 函数,它只接受一个参数

有关更多讨论,请参见 Allen Wirfs-Brock 的 A JavaScript optional argument hazard

映射的数组包含 undefined

map() 方法用于 Array 实例,它创建一个新的数组,该数组填充了对调用数组中每个元素调用提供的函数的结果。
const numbers = [1, 2, 3, 4];
const filteredNumbers = numbers.map((num, index) => {
  if (index < 3) {
    return num;
  }
});

// index goes from 0, so the filterNumbers are 1,2,3 and undefined.
// filteredNumbers is [1, 2, 3, undefined]
// numbers is still [1, 2, 3, 4]

当返回 undefined 或任何内容时,结果数组将包含 undefined。如果你想删除该元素,请链接一个 filter() 方法,或使用 flatMap() 方法并返回一个空数组来表示删除。

有副作用的映射

map() 方法用于 Array 实例,它创建一个新的数组,该数组填充了对调用数组中每个元素调用提供的函数的结果。
const cart = [5, 15, 25];
let total = 0;
const withTax = cart.map((cost) => {
  total += cost;
  return cost * 1.2;
});
console.log(withTax); // [6, 18, 30]
console.log(total); // 45

回调函数可以有副作用。

map() 方法用于 Array 实例,它创建一个新的数组,该数组填充了对调用数组中每个元素调用提供的函数的结果。
const cart = [5, 15, 25];
const total = cart.reduce((acc, cost) => acc + cost, 0);
const withTax = cart.map((cost) => cost * 1.2);

不建议这样做,因为复制方法最好与纯函数一起使用。在这种情况下,我们可以选择对数组进行两次迭代。

map() 方法用于 Array 实例,它创建一个新的数组,该数组填充了对调用数组中每个元素调用提供的函数的结果。
const products = [
  { name: "sports car" },
  { name: "laptop" },
  { name: "phone" },
];

products.map((product) => {
  product.price = 100;
});

有时这种模式会走到极端,map() 唯一有用的功能就是引起副作用。

map() 方法用于 Array 实例,它创建一个新的数组,该数组填充了对调用数组中每个元素调用提供的函数的结果。
products.forEach((product) => {
  product.price = 100;
});

如前所述,这是一种反模式。如果你不使用 map() 的返回值,请改用 forEach()for...of 循环。

map() 方法用于 Array 实例,它创建一个新的数组,该数组填充了对调用数组中每个元素调用提供的函数的结果。
const productsWithPrice = products.map((product) => {
  return { ...product, price: 100 };
});

或者,如果你想创建一个新数组

使用 callbackFn 的第三个参数

map() 方法用于 Array 实例,它创建一个新的数组,该数组填充了对调用数组中每个元素调用提供的函数的结果。
const numbers = [3, -1, 1, 4, 1, 5, 9, 2, 6];
const averaged = numbers
  .filter((num) => num > 0)
  .map((num, idx, arr) => {
    // Without the arr argument, there's no way to easily access the
    // intermediate array without saving it to a variable.
    const prev = arr[idx - 1];
    const next = arr[idx + 1];
    let count = 1;
    let total = num;
    if (prev !== undefined) {
      count++;
      total += prev;
    }
    if (next !== undefined) {
      count++;
      total += next;
    }
    const average = total / count;
    // Keep two decimal places
    return Math.round(average * 100) / 100;
  });
console.log(averaged); // [2, 2.67, 2, 3.33, 5, 5.33, 5.67, 4]

array 参数在你想访问数组中的另一个元素时很有用,尤其是在你没有引用该数组的现有变量时。以下示例首先使用 filter() 提取正值,然后使用 map() 创建一个新数组,其中每个元素都是其邻居和自身的平均值。

array 参数不是正在构建的数组——无法从回调函数中访问正在构建的数组。

在稀疏数组上使用 map()

map() 方法用于 Array 实例,它创建一个新的数组,该数组填充了对调用数组中每个元素调用提供的函数的结果。
console.log(
  [1, , 3].map((x, index) => {
    console.log(`Visit ${index}`);
    return x * 2;
  }),
);
// Visit 0
// Visit 2
// [2, empty, 6]

稀疏数组在 map() 后仍然是稀疏的。返回的数组中空槽的索引仍然为空,回调函数不会在它们上调用。

在非数组对象上调用 map()

map() 方法用于 Array 实例,它创建一个新的数组,该数组填充了对调用数组中每个元素调用提供的函数的结果。
const arrayLike = {
  length: 3,
  0: 2,
  1: 3,
  2: 4,
  3: 5, // ignored by map() since length is 3
};
console.log(Array.prototype.map.call(arrayLike, (x) => x ** 2));
// [ 4, 9, 16 ]

map() 方法读取 thislength 属性,然后访问每个键为非负整数且小于 length 的属性。

map() 方法用于 Array 实例,它创建一个新的数组,该数组填充了对调用数组中每个元素调用提供的函数的结果。
const elems = document.querySelectorAll("select option:checked");
const values = Array.prototype.map.call(elems, ({ value }) => value);

此示例展示了如何遍历由 querySelectorAll 收集的对象集合。这是因为 querySelectorAll 返回一个 NodeList(这是对象的集合)。在这种情况下,我们在屏幕上返回所有选定的 option 的值

规范

你也可以使用 Array.from()elems 转换为数组,然后访问 map() 方法。
规范
# ECMAScript 语言规范

浏览器兼容性

sec-array.prototype.map

另请参阅