試一試
const array = [1, 4, 9, 16];
// Pass a function to map
const mapped = array.map((x) => x * 2);
console.log(mapped);
// Expected output: Array [2, 8, 18, 32]
語法
map(callbackFn)
map(callbackFn, thisArg)
引數
callbackFn-
為陣列中的每個元素執行的函式。它的返回值將作為新陣列中的一個元素。該函式以以下引數呼叫:
thisArg可選-
在執行
callbackFn時用作this的值。請參閱 迭代方法。
返回值
一個新陣列,其中每個元素都是回撥函式的結果。
描述
map() 方法是一個迭代方法。它對陣列中的每個元素呼叫一次提供的 callbackFn 函式,並根據結果構建一個新陣列。有關這些方法通常如何工作的更多資訊,請閱讀迭代方法部分。
callbackFn 僅對具有已賦值的陣列索引呼叫。對於稀疏陣列中的空槽,它不會被呼叫。
map() 方法是通用的。它只期望 this 值具有 length 屬性和整數鍵屬性。
示例
將數字陣列對映到平方根陣列
以下程式碼將一個數字陣列轉換為一個新陣列,新陣列包含第一個陣列中數字的平方根。
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 重新格式化陣列中的物件
以下程式碼將一個物件陣列轉換為一個新陣列,新陣列包含重新格式化後的物件。
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() 一起使用
通常使用只有一個引數的回撥函式(正在遍歷的元素)。某些函式也經常與一個引數一起使用,即使它們接受額外的可選引數。這些習慣可能導致令人困惑的行為。請考慮以下示例:
["1", "2", "3"].map(parseInt);
儘管你可能期望結果是 [1, 2, 3],但實際結果是 [1, NaN, NaN]。
parseInt 通常只用一個引數呼叫,但它接受兩個引數。第一個引數是表示式,第二個引數是基數。對於回撥函式,Array.prototype.map 傳遞 3 個引數:元素、索引和陣列。第三個引數被 parseInt 忽略——但第二個引數不會被忽略!這是可能產生混淆的原因。
以下是一個簡潔的迭代步驟示例:
/* 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
為了解決這個問題,可以定義另一個只接受一個引數的函式:
["1", "2", "3"].map((str) => parseInt(str, 10)); // [1, 2, 3]
你也可以使用 Number 函式,它只接受一個引數:
["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]
請參閱 Allen Wirfs-Brock 的 JavaScript 可選引數的危險,以獲取更多討論。
對映的陣列包含 undefined
當返回 undefined 或不返回任何內容時,結果陣列將包含 undefined。如果你想刪除該元素,可以連結一個 filter() 方法,或者使用 flatMap() 方法並返回一個空陣列來表示刪除。
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]
有副作用的對映
回撥函式可以有副作用。
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
這並不推薦,因為複製方法最好與純函式一起使用。在這種情況下,我們可以選擇迭代陣列兩次。
const cart = [5, 15, 25];
const total = cart.reduce((acc, cost) => acc + cost, 0);
const withTax = cart.map((cost) => cost * 1.2);
有時這種模式會走到極端,而 map() 唯一有用的地方就是引起副作用。
const products = [
{ name: "sports car" },
{ name: "laptop" },
{ name: "phone" },
];
products.map((product) => {
product.price = 100;
});
如前所述,這是一種反模式。如果你不使用 map() 的返回值,請改用 forEach() 或 for...of 迴圈。
products.forEach((product) => {
product.price = 100;
});
或者,如果你想建立一個新陣列,可以這樣做:
const productsWithPrice = products.map((product) => ({
...product,
price: 100,
}));
使用 callbackFn 的第三個引數
當你想訪問陣列中的另一個元素時,array 引數非常有用,尤其是在你沒有一個引用該陣列的現有變數時。以下示例首先使用 filter() 提取正值,然後使用 map() 建立一個新陣列,新陣列中的每個元素都是其鄰居和它本身的平均值。
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 引數不是正在構建的陣列——無法從回撥函式訪問正在構建的陣列。
在稀疏陣列上使用 map()
稀疏陣列在 map() 之後仍然是稀疏的。空槽的索引在返回的陣列中仍然是空的,並且回撥函式不會在它們上面被呼叫。
console.log(
[1, , 3].map((x, index) => {
console.log(`Visit ${index}`);
return x * 2;
}),
);
// Visit 0
// Visit 2
// [2, empty, 6]
在非陣列物件上呼叫 map()
map() 方法讀取 this 的 length 屬性,然後訪問鍵為小於 length 的非負整數的每個屬性。
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 ]
此示例演示瞭如何遍歷由 querySelectorAll 收集的物件集合。這是因為 querySelectorAll 返回一個 NodeList(這是一個物件集合)。在這種情況下,我們返回螢幕上所有選定 option 的值。
const elems = document.querySelectorAll("select option:checked");
const values = Array.prototype.map.call(elems, ({ value }) => value);
你也可以使用 Array.from() 將 elems 轉換為陣列,然後訪問 map() 方法。
規範
| 規範 |
|---|
| ECMAScript® 2026 語言規範 # sec-array.prototype.map |
瀏覽器相容性
載入中…