IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

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

    张 鑫旭发表于 2024-09-19 15:32:18
    love 0

    by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11357
    本文可全文转载,独立域名个人网站无需授权,但需要保留原作者、出处以及文中链接,任何网站均可摘要聚合,商用请联系授权。

    封面图

    一、原生分组方法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这东西,可以有很多精彩的案例示意,会有众多衍生的表现。

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

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

    好,就说这些吧。

    感谢阅读,欢迎。

    元瑶

    本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
    本文地址:https://www.zhangxinxu.com/wordpress/?p=11357

    (本篇完)



沪ICP备19023445号-2号
友情链接