咳咳,各位观众,各位大佬,晚上好!我是今天的主讲人,江湖人称“代码界的段子手”。今天咱们不聊风花雪月,就来唠唠 JavaScript 里呼声很高的新提案:Array Grouping,特别是里面的 groupBy
和 groupToMap
这两位“分组小能手”。
说起分组,这事儿咱们在日常开发中肯定没少干。比如说,你有一堆用户数据,想按性别分成男女两拨;或者你有一堆订单数据,想按月份统计一下销售额。以前咋办?是不是得吭哧吭哧地写循环,写判断,写对象,一不小心还得踩几个坑?
现在好了,有了 groupBy
和 groupToMap
,这些烦恼统统扫光!它们就像两位武林高手,一个擅长快刀斩乱麻,一个擅长精雕细琢,都能帮你把数组数据安排得明明白白。
一、groupBy
: 简洁明了,分组界的“大众情人”
先来说说 groupBy
。这玩意儿的特点就是一个字:简单。它接收一个回调函数作为参数,这个回调函数决定了分组的依据。groupBy
会遍历数组中的每一个元素,把元素传给回调函数,回调函数返回的值就是这个元素所属的组的 key。最后,groupBy
会返回一个对象,这个对象的 key 就是分组的 key,value 就是属于这个组的元素组成的数组。
是不是有点绕?没关系,上代码,一看就懂:
const products = [
{ name: 'iPhone', category: 'Electronics', price: 999 },
{ name: 'Samsung Galaxy', category: 'Electronics', price: 899 },
{ name: 'T-shirt', category: 'Clothing', price: 20 },
{ name: 'Jeans', category: 'Clothing', price: 50 },
{ name: 'Book', category: 'Books', price: 15 }
];
const groupedProducts = products.groupBy(product => product.category);
console.log(groupedProducts);
/*
{
Electronics: [
{ name: 'iPhone', category: 'Electronics', price: 999 },
{ name: 'Samsung Galaxy', category: 'Electronics', price: 899 }
],
Clothing: [
{ name: 'T-shirt', category: 'Clothing', price: 20 },
{ name: 'Jeans', category: 'Clothing', price: 50 }
],
Books: [
{ name: 'Book', category: 'Books', price: 15 }
]
}
*/
看,多简单!一行代码搞定分组! groupBy
就像个老好人,你给他一个分组的规则,他就老老实实地把数据分好,然后打包成一个对象给你。
用例一:按年龄段分组用户
const users = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 32 },
{ name: 'Charlie', age: 18 },
{ name: 'David', age: 45 },
{ name: 'Eve', age: 22 }
];
const groupedUsers = users.groupBy(user => {
if (user.age < 25) {
return 'Young';
} else if (user.age < 40) {
return 'Mid-age';
} else {
return 'Old';
}
});
console.log(groupedUsers);
/*
{
Young: [
{ name: 'Alice', age: 25 },
{ name: 'Charlie', age: 18 },
{ name: 'Eve', age: 22 }
],
'Mid-age': [ { name: 'Bob', age: 32 } ],
Old: [ { name: 'David', age: 45 } ]
}
*/
用例二:按奇偶分组数字
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const groupedNumbers = numbers.groupBy(number => number % 2 === 0 ? 'Even' : 'Odd');
console.log(groupedNumbers);
/*
{
Odd: [ 1, 3, 5, 7, 9 ],
Even: [ 2, 4, 6, 8, 10 ]
}
*/
怎么样,是不是感觉 groupBy
特别亲民?它适用于大多数简单的分组场景,让你告别繁琐的循环和判断。
二、groupToMap
: 精益求精,分组界的“技术大牛”
接下来,咱们聊聊 groupToMap
。和 groupBy
相比,groupToMap
就像一位精益求精的技术大牛。它也接收一个回调函数作为参数,这个回调函数同样决定了分组的依据。但是,groupToMap
返回的不是一个对象,而是一个 Map
对象。
Map
对象有什么好处呢?
- Key 的类型更自由: 对象的 key 只能是字符串或 Symbol,而
Map
的 key 可以是任意类型,包括对象、函数等等。 - 顺序性:
Map
对象会保留 key 的插入顺序,而对象的 key 是无序的(虽然现在大多数浏览器会按照插入顺序遍历对象的 key,但这并不是规范要求的)。 - 性能: 在某些场景下,
Map
对象的性能可能比普通对象更好,尤其是在 key 的数量非常大的时候。
总的来说,groupToMap
更加灵活,也更适合一些特殊的场景。
还是上代码:
const products = [
{ name: 'iPhone', category: 'Electronics', price: 999 },
{ name: 'Samsung Galaxy', category: 'Electronics', price: 899 },
{ name: 'T-shirt', category: 'Clothing', price: 20 },
{ name: 'Jeans', category: 'Clothing', price: 50 },
{ name: 'Book', category: 'Books', price: 15 }
];
const groupedProducts = products.groupToMap(product => product.category);
console.log(groupedProducts);
/*
Map(3) {
'Electronics' => [
{ name: 'iPhone', category: 'Electronics', price: 999 },
{ name: 'Samsung Galaxy', category: 'Electronics', price: 899 }
],
'Clothing' => [
{ name: 'T-shirt', category: 'Clothing', price: 20 },
{ name: 'Jeans', category: 'Clothing', price: 50 }
],
'Books' => [ { name: 'Book', category: 'Books', price: 15 } ]
}
*/
可以看到,groupToMap
返回的是一个 Map
对象,它的 key 是分类名称,value 是属于该分类的商品组成的数组。
用例一:使用对象作为 Key 进行分组
假设我们有一个包含学生信息的数组,每个学生都有一个 grade
属性,表示年级。我们想按照年级进行分组,但是年级本身是一个对象,包含 name
和 level
两个属性。
const students = [
{ name: 'Alice', grade: { name: '一年级', level: 1 } },
{ name: 'Bob', grade: { name: '二年级', level: 2 } },
{ name: 'Charlie', grade: { name: '一年级', level: 1 } },
{ name: 'David', grade: { name: '三年级', level: 3 } },
{ name: 'Eve', grade: { name: '二年级', level: 2 } }
];
const groupedStudents = students.groupToMap(student => student.grade);
console.log(groupedStudents);
/*
Map(3) {
{ name: '一年级', level: 1 } => [
{ name: 'Alice', grade: { name: '一年级', level: 1 } },
{ name: 'Charlie', grade: { name: '一年级', level: 1 } }
],
{ name: '二年级', level: 2 } => [
{ name: 'Bob', grade: { name: '二年级', level: 2 } },
{ name: 'Eve', grade: { name: '二年级', level: 2 } }
],
{ name: '三年级', level: 3 } => [
{ name: 'David', grade: { name: '三年级', level: 3 } }
]
}
*/
在这个例子中,我们使用 grade
对象作为 Map
的 key,这样就可以方便地按照年级进行分组了。
用例二:需要保留插入顺序的分组
假设我们有一个包含日志信息的数组,每条日志都有一个 timestamp
属性,表示日志的创建时间。我们想按照小时进行分组,并且需要保留日志的插入顺序。
const logs = [
{ message: 'Log 1', timestamp: new Date('2023-10-27T10:30:00') },
{ message: 'Log 2', timestamp: new Date('2023-10-27T10:45:00') },
{ message: 'Log 3', timestamp: new Date('2023-10-27T11:00:00') },
{ message: 'Log 4', timestamp: new Date('2023-10-27T11:15:00') },
{ message: 'Log 5', timestamp: new Date('2023-10-27T10:15:00') }
];
const groupedLogs = logs.groupToMap(log => log.timestamp.getHours());
console.log(groupedLogs);
/*
Map(2) {
10 => [
{ message: 'Log 1', timestamp: 2023-10-27T02:30:00.000Z },
{ message: 'Log 2', timestamp: 2023-10-27T02:45:00.000Z },
{ message: 'Log 5', timestamp: 2023-10-27T02:15:00.000Z }
],
11 => [
{ message: 'Log 3', timestamp: 2023-10-27T03:00:00.000Z },
{ message: 'Log 4', timestamp: 2023-10-27T03:15:00.000Z }
]
}
*/
在这个例子中,我们使用 groupToMap
来按照小时进行分组,并且 Map
对象会保留日志的插入顺序,这样我们就可以按照时间顺序来查看每个小时的日志信息了。注意 Map
只会保持key的插入顺序,组内的元素顺序还是原始顺序。
三、groupBy
vs groupToMap
: 如何选择?
那么,在实际开发中,我们应该选择 groupBy
还是 groupToMap
呢? 别急,我给你总结了一个表格,让你一目了然:
特性 | groupBy |
groupToMap |
---|---|---|
返回值类型 | 普通对象 | Map 对象 |
Key 的类型 | 只能是字符串或 Symbol | 可以是任意类型 |
顺序性 | 无序(虽然现在大多数浏览器会按照插入顺序遍历) | 保留 key 的插入顺序 |
性能 | 一般情况下足够用 | 在 key 的数量非常大的时候可能更好 |
适用场景 | 简单分组,对 key 的类型和顺序没有特殊要求 | 需要使用对象作为 key,或者需要保留插入顺序 |
总的来说,如果你的分组需求比较简单,对 key 的类型和顺序没有特殊要求,那么 groupBy
就能满足你的需求。如果你的分组需求比较复杂,需要使用对象作为 key,或者需要保留插入顺序,那么 groupToMap
才是你的最佳选择。
四、兼容性考虑
需要注意的是,groupBy
和 groupToMap
目前还是提案阶段,还没有被所有浏览器原生支持。如果你想在现有的项目中使用它们,可以使用 polyfill 或者使用一些第三方库来实现类似的功能。
例如,你可以使用 core-js
来提供 polyfill:
npm install core-js
然后在你的代码中引入 polyfill:
import 'core-js/features/array/group';
import 'core-js/features/array/group-to-map';
// 现在你就可以使用 groupBy 和 groupToMap 了
五、总结
好了,今天的讲座就到这里了。希望通过今天的讲解,大家对 JavaScript 的 groupBy
和 groupToMap
有了更深入的了解。记住,它们就像两位分组界的“武林高手”,一个简洁明了,一个精益求精,都能帮你轻松搞定数组分组!
记住,写代码就像写段子,要简洁,要幽默,要让人一看就懂! 咱们下期再见!