新特性解决的问题
我们在处理数据库返回的数据时,时常要做各种分组聚合,举例如下:
const inventory = [
{ name: "asparagus", type: "vegetables", quantity: 5 },
{ name: "bananas", type: "fruit", quantity: 0 },
{ name: "goat", type: "meat", quantity: 23 },
{ name: "cherries", type: "fruit", quantity: 5 },
{ name: "fish", type: "meat", quantity: 22 },
];
假如现在数据库中存储了上述的各种不同的食物名称、分类和数量。
现在UI界面要求按照不同分类分别列出食物和其数量。 对于前端来说,肯定是希望这样一个数据结构:
{
vegetables: [
{ name: 'asparagus', type: 'vegetables', quantity: 5 },
],
fruit: [
{ name: "bananas", type: "fruit", quantity: 0 },
{ name: "cherries", type: "fruit", quantity: 5 }
],
meat: [
{ name: "goat", type: "meat", quantity: 23 },
{ name: "fish", type: "meat", quantity: 22 }
]
}
以上数据结构按照蔬菜 水果 肉对数据进行了分类,这样前端按照不同分类列出食物和数量就变得非常轻松了。
要做这种处理,在以前我们需要另外定义一个空对象,然后遍历数据往对象里添加键和数组值,要做非空判断。虽然不难,但是繁琐,费神。
现在我们有了Object.groupBy,一切就变得简单了:
const result = Object.groupBy(inventory, ({ type }) => type);
一行代码搞定。这行代码会按照type来做分组聚合。
这就是新特性:Object.groupBy。
如果你用过Lodash,相信你已经对这种功能比较熟悉了。
Object.groupBy
从上面的例子可以看出,Object.groupBy可以对目标数据集进行分组聚合。
下面咱们来看一下它的具体用法。
语法
Object.groupBy(items, callbackFn)
参数
items:
第一个参数items代表需要处理的可迭代对象,例如:数组。
callbackFn:
第二个参数callbackFn代表callback函数。
callbackFn的参数:
1. element:数组中的元素。
2. index:element的数组索引。
callbackFn的返回值规则:
callbackFn必须有返回值,每个返回值都会作为最终返回对象的键名。如果多条数据的键名相同,则其值以数组的形式叠加起来。
由于是用来做键名,因此返回值最好是字符串或者Symbol类型,如果不是这两种类型之一,将被强制转换成字符串类型。
如果没有返回值,那undefined会被作为返回值。
返回值
返回值是一个对象,对象的键名是callbackFn函数的返回值,键值是每个callbackFn函数的返回值所对应的数组项组成的数组。
所以说Object.groupBy做的事就是对目标数组进行分组。
返回对象的原型是null,而不是Object.prototype。
Object.create(null)创建的就是一个原型为null的对象。
这就意味着对象中常用的方法不能在Object.groupBy上使用。
例如:
const o = Object.groupBy(...);
o.hasOwnProperty('xxx');
这里会报错hasOwnProperty不是一个函数。
像这样创建的对象,其原型是Object.prototype,具有hasOwnProperty方法:
let o = {};
// true
Object.getPrototypeOf(o) === Object.prototype;
// o.hasOwnProperty 存在
为什么要这样呢?是因为怕对象中的属性和Object.prototype的属性重名导致冲突,所以干脆抛弃了Object。
文字表达太苍白了,说得太多只会让大家困扰,很不容易理解。我们再用一个最简洁的例子来说明它的用法:
const array = [1, 2, 3, 4, 5];
const groupedResult = Object.groupBy(array, (num, index) => {
return num % 2 === 0 ? 'even': 'odd';
});
// groupedResult是: { odd: [1, 3, 5], even: [2, 4] }
相信看到这里你已经知道它的用法了。
为什么不是Array.groupBy或者Array.prototype.groupBy
其实上面咱们也说过,groupBy其实不只是适用于数组,它适用于所有的可迭代对象,另外它返回的是一个对象,因此放在Object下是比较合适的。
浏览器兼容性
目前该特性已经到了 Stage 4 阶段,欲了解 Stage 4 的含义可以看这篇文章 各大主流浏览器也是刚刚开始支持。
Polyfill
corejs已经有对应的Polyfill。
结束语
ES2024系列专辑将持续更新将在2024年发布的新特性。敬请关注!
注:以上例子部分参考了MDN。