实用的JS对象分组静态方法Object.groupBy()

这篇文章发布于 2024年09月19日,星期四,23:32,归类于 JS API。 阅读 3283 次, 今日 9 次 2 条评论

 

封面图

一、原生分组方法Object.groupBy()

好消息,所有现代浏览器都已经支持浏览器原生的静态方法Object.groupBy()了,如下图所示,Safari浏览器支持最晚,今年4月份才开始支持。

groupBy兼容性

这就意味着最晚明年,就算不使用Polyfill代码,也能在生产环境使用该方法了。

作用

Object.groupBy()可以让可枚举对象,根据某个键进行自动分组。

例如:

const data = [{
    id: 1,
    name: '张三'
}, {
    id: 3,
    name: '李四'
}, {
    id: 4,
    name: '王二'
}, {
    id: 2,
    name: '张三'
}];

const result = Object.groupBy(data, ({ name}) => name);

console.log(result);

输入结果则是:

{张三: Array(2), 李四: Array(1), 王二: Array(1)}
张三: Array(2)
0: {id: 1, name: '张三'}
1: {id: 2, name: '张三'}
length: 2
[[Prototype]]: Array(0)
李四: Array(1)
0: {id: 3, name: '李四'}
length: 1
[[Prototype]]: Array(0)
王二: Array(1)
0: {id: 4, name: '王二'}
length: 1
[[Prototype]]: Array(0)

截图如下:

分组输出结果

语法

Object.groupBy(items, callbackFn)
items
将被分组的可迭代对象。
callbackFn(element, index)
为可迭代对象中的每个元素执行的函数。其返回值会被作为键,用来指向分组后的数组项。使用以下参数调用该函数:

Polyfill代码

如果要兼容陈旧浏览器,可以试试使用这段JavaScript代码:

const hasGroup = typeof Object.groupBy === typeof undefined || typeof Array.groupToMap === typeof undefined || typeof Array.group === typeof undefined;
if (!hasGroup) {
  const groupBy = (arr, callback) => {
    return arr.reduce((acc = {}, ...args) => {
      const key = callback(...args);
      acc[key] ??= []
      acc[key].push(args[0]);
      return acc;
    }, {});
  };

  if (typeof Object.groupBy === typeof undefined) {
    Object.groupBy = groupBy;
  }

  if (typeof Array.groupToMap === typeof undefined) {
    Array.groupToMap = groupBy;
  }

  if (typeof Array.group === typeof undefined) {
    Array.group = groupBy;
  }
}

二、实际案例

我在某项目开发中已经使用过此API了,给大家演示下使用场景。

已知有数组:

const okrAlignList = [{
    objectId: 1,
    empNum: 'YW001',
    empName: '刘一'
}, {
    objectId: 3,
    empNum: 'YW002',
    empName: '姚二三'
}, {
    objectId: 4,
    empNum: 'YW003',
    empName: '张鑫旭'
}, {
    objectId: 2,
    empNum: 'YW001',
    empName: '刘一'
}]

然后页面渲染的时候,如果是同一人,是需要合并展示的,如配图所示。

人名截图示意

此时,我们就可以直接使用Object.groupBy()方法进行渲染,而不需要自己额外写一个分组方法了,此时的Vue模板渲染使用下面的就可以了:

<data 
  v-for="(value, key) in Object.groupBy(okrAlignList, obj => obj.empNum)"
  :key="key"
>
  {{ value[0].empName }}<output v-if="value.length > 1">
    ({{ value.length}})
  </output>
</data>

代码简洁多了。

三、还有Map.groupBy()方法

除了Object对象有groupBy()静态方法,Map对象也有,兼容性一致,语法也是一样的。

使用示意:

const inventory = [
  { name: 'asparagus', type: 'vegetables', quantity: 9 },
  { name: 'bananas', type: 'fruit', quantity: 5 },
  { name: 'goat', type: 'meat', quantity: 23 },
  { name: 'cherries', type: 'fruit', quantity: 12 },
  { name: 'fish', type: 'meat', quantity: 22 },
];

const restock = { restock: true };
const sufficient = { restock: false };
const result = Map.groupBy(inventory, ({ quantity }) =>
  quantity < 6 ? restock : sufficient,
);
console.log(result.get(restock));
// [{ name: "bananas", type: "fruit", quantity: 5 }]

Map.groupBy()使用用在分组信息会随时间变化的场景下,因为即使对象被修改,它仍将继续作为返回Map的键。

其他时候,换成使用Object.groupBy()实现也是可以的。

四、噢啦,结束了,就这些

好了,就这点内容,算是我众多文章里面比较水的一篇了吧。

我一般较少介绍纯JavaScript语言的API就是这个原因。

就是干巴巴的语法这些,都是其他地方都能找到的。

不像CSS这东西,可以有很多精彩的案例示意,会有众多衍生的表现。

总之,重要的是让大家知道浏览器新支持了个这么玩意。

日后在开发项目的时候,可以省掉些代码,提高点编码速度。

好,就说这些吧。

感谢阅读,欢迎

元瑶

(本篇完)

分享到:


发表评论(目前2 条评论)

  1. RowlingJoe说道:

    念头通达,阁下肯定是正派修士吧

  2. yukyao说道:

    旭哥,实际案例中,v-for 那里的{{ value[0].empName }}应该可以直接取key吧,?