ECMAScript 2024 (ES15) 引入了一個(gè)極具潛力的新特性:Map.groupBy(),它大大簡(jiǎn)化了數(shù)據(jù)分組的操作。無(wú)論是在處理數(shù)組、對(duì)象,還是更復(fù)雜的業(yè)務(wù)邏輯中,分組操作都是開(kāi)發(fā)中常見(jiàn)的需求。本文將通過(guò)詳細(xì)的技術(shù)案例和代碼展示,為你剖析 Map.groupBy() 的強(qiáng)大之處。
什么是 Map.groupBy()?
Map.groupBy() 是 JavaScript 新增的靜態(tài)方法,用于從一個(gè)可迭代對(duì)象(如數(shù)組)中創(chuàng)建一個(gè) Map,并根據(jù)指定的分組邏輯,將數(shù)據(jù)分組到對(duì)應(yīng)的鍵中。每個(gè)鍵對(duì)應(yīng)一個(gè)數(shù)組,包含所有被分到該組的數(shù)據(jù)。
語(yǔ)法如下:
Map.groupBy(iterable, callbackFn)
- iterable: 任何可迭代對(duì)象(如數(shù)組、字符串等)。
-
callbackFn: 回調(diào)函數(shù),用于生成分組的鍵。格式為
callbackFn(element, index)。
返回值是一個(gè) Map,其中:
- 鍵是分組鍵,由
callbackFn決定。 - 值是一個(gè)數(shù)組,包含屬于該組的所有元素。
目前該新特性兼容性如下:

使用場(chǎng)景解析
1. 按條件分組
假設(shè)我們有一個(gè)學(xué)生成績(jī)數(shù)組,想按成績(jī)的及格與否進(jìn)行分組。
const scores = [
{ name: 'Alice', score: 85 },
{ name: 'Bob', score: 40 },
{ name: 'Charlie', score: 90 },
{ name: 'Dave', score: 30 }
];
const groupedByPass = Map.groupBy(scores, student => student.score >= 60 ? 'pass' : 'fail');
console.log(groupedByPass);
// 輸出:
// Map {
// 'pass' => [
// { name: 'Alice', score: 85 },
// { name: 'Charlie', score: 90 }
// ],
// 'fail' => [
// { name: 'Bob', score: 40 },
// { name: 'Dave', score: 30 }
// ]
// }
這里,callbackFn 返回的鍵是字符串 'pass' 或 'fail',分別對(duì)應(yīng)及格與不及格的分組。
2. 按屬性分組
我們有一個(gè)商品列表,希望根據(jù)商品的類(lèi)別進(jìn)行分組:
const products = [
{ name: 'Laptop', category: 'Electronics' },
{ name: 'Phone', category: 'Electronics' },
{ name: 'Shirt', category: 'Clothing' },
{ name: 'Pants', category: 'Clothing' }
];
const groupedByCategory = Map.groupBy(products, product => product.category);
console.log(groupedByCategory);
// 輸出:
// Map {
// 'Electronics' => [
// { name: 'Laptop', category: 'Electronics' },
// { name: 'Phone', category: 'Electronics' }
// ],
// 'Clothing' => [
// { name: 'Shirt', category: 'Clothing' },
// { name: 'Pants', category: 'Clothing' }
// ]
// }
這種分組方式非常適合電商、庫(kù)存管理等場(chǎng)景。
3. 復(fù)雜鍵的分組
分組鍵不僅限于簡(jiǎn)單的字符串,也可以是對(duì)象或其他復(fù)雜類(lèi)型。
const events = [
{ title: 'Meeting', date: new Date('2025-01-01') },
{ title: 'Conference', date: new Date('2025-01-02') },
{ title: 'Workshop', date: new Date('2025-01-01') }
];
const groupedByDate = Map.groupBy(events, event => event.date.toISOString());
console.log(groupedByDate);
// 輸出:
// Map {
// '2025-01-01T00:00:00.000Z' => [
// { title: 'Meeting', date: 2025-01-01T00:00:00.000Z },
// { title: 'Workshop', date: 2025-01-01T00:00:00.000Z }
// ],
// '2025-01-02T00:00:00.000Z' => [
// { title: 'Conference', date: 2025-01-02T00:00:00.000Z }
// ]
// }
callbackFn 使用了 toISOString() 方法,將日期對(duì)象轉(zhuǎn)換為字符串形式,方便作為分組鍵。
深入對(duì)比 reduce 的替代性
在 Map.groupBy() 推出之前,我們通常使用 reduce 來(lái)實(shí)現(xiàn)分組操作。
以下是用 reduce 實(shí)現(xiàn)的分組代碼:
const scores = [
{ name: 'Alice', score: 85 },
{ name: 'Bob', score: 40 },
{ name: 'Charlie', score: 90 },
{ name: 'Dave', score: 30 }
];
const groupedByReduce = scores.reduce((group, student) => {
const key = student.score >= 60 ? 'pass' : 'fail';
if (!group[key]) {
group[key] = [];
}
group[key].push(student);
return group;
}, {});
console.log(groupedByReduce);
// 輸出:
// {
// pass: [
// { name: 'Alice', score: 85 },
// { name: 'Charlie', score: 90 }
// ],
// fail: [
// { name: 'Bob', score: 40 },
// { name: 'Dave', score: 30 }
// ]
// }
雖然 reduce 功能強(qiáng)大,但使用起來(lái)容易冗長(zhǎng),Map.groupBy() 則更簡(jiǎn)潔優(yōu)雅,并且返回的是 Map 對(duì)象,提供了更多操作的可能性。
性能與最佳實(shí)踐
性能
-
Map.groupBy()的優(yōu)勢(shì):-
Map的鍵可以是任意值(包括對(duì)象),而Object的鍵只能是字符串或符號(hào)。 -
Map的鍵值查找和插入效率高,適合處理大量數(shù)據(jù)。
-
-
reduce的局限:- 手動(dòng)處理數(shù)據(jù)結(jié)構(gòu)容易出錯(cuò)。
- 性能略遜于專(zhuān)門(mén)為分組設(shè)計(jì)的
Map.groupBy()。
最佳實(shí)踐
- 使用
Map.groupBy()時(shí),確保callbackFn簡(jiǎn)單易懂,避免過(guò)于復(fù)雜的邏輯。 - 分組鍵應(yīng)盡量唯一且明確,避免不必要的沖突。
小結(jié)
Map.groupBy() 是 ECMAScript 2024 中極為實(shí)用的特性,它簡(jiǎn)化了數(shù)據(jù)分組的操作,提高了代碼的可讀性和維護(hù)性。在處理復(fù)雜分組需求時(shí),它能讓開(kāi)發(fā)者事半功倍。
如果你還在用傳統(tǒng)的 reduce 實(shí)現(xiàn)分組,不妨試試這個(gè)全新的方法,感受現(xiàn)代 JavaScript 的魅力!
當(dāng)然你也在學(xué)習(xí)前端和鴻蒙等技術(shù),不妨關(guān)注我,我們一起學(xué)習(xí)進(jìn)步。(≧▽≦)/