JavaScript正在拥有数组的分组方法

本文为翻译文章,原文为: JAVASCRIPT IS GETTING ARRAY GROUPING METHODS是 Phil Nash发布于2023年9月14日的文章。

在数组中对元素进行分组可能是我们已经做过很多次的事情之一。每次都需要手工编写分组函数,或者使用 loash 的 groupBy 函数

一个好消息是: JavaScript 现在正在获得分组方法。所以您不再需要像之前那样做了。Object.GroupByMap.groupBy 是新的方法,它们可以使分组变得更容易,节省我们的时间或依赖项。

现有的分组方法

假设你有一个代表人的对象数组,你想根据他们的年龄对他们进行分组。您可以像下面这样使用 forEach 循环:

javascript 复制代码
const people = [
  { name: "Alice", age: 28 },
  { name: "Bob", age: 30 },
  { name: "Eve", age: 28 },
];

const peopleByAge = {};

people.forEach((person) => {
  const age = person.age;
  if (!peopleByAge[age]) {
    peopleByAge[age] = [];
  }
  peopleByAge[age].push(person);
});
console.log(peopleByAge);
/*
{
  "28": [{"name":"Alice","age":28}, {"name":"Eve","age":28}],
  "30": [{"name":"Bob","age":30}]
}
*/

或者你可以选择用 reduce,像这样:

javascript 复制代码
const peopleByAge = people.reduce((acc, person) => {
  const age = person.age;
  if (!acc[age]) {
    acc[age] = [];
  }
  acc[age].push(person);
  return acc;
}, {});

不管怎样,这代码都有点尴尬。必须始终检查对象以查看分组的键是否存在,如果不存在,则使用空数组创建分组键。然后可以将该项推入数组。

使用OBJECT.GROUPBY进行分组

使用新的 Object.groupBy 方法,您可以这样做:

javascript 复制代码
const peopleByAge = Object.groupBy(people, (person) => person.age);

简单多了! 虽然有些事情需要注意:

GroupBy 返回一个原型为空(null)的对象。这意味着该对象不继承 Object.prototype 的任何属性。这样设计的好处是您不会意外地覆盖 Object.prototype 上的任何属性。但是这也意味着对象没有您可能期望的任何方法,比如 hasOwnProperty 或 toString。例如:

javascript 复制代码
const peopleByAge = Object.groupBy(people, (person) => person.age);
console.log(peopleByAge.hasOwnProperty("28"));
// TypeError: peopleByAge.hasOwnProperty is not a function

传递给 Object.groupBy 的回调函数应该返回字符串或Symbol。如果它返回任何其他内容,它将被强制转换为一个字符串。

在示例中,将年龄作为一个数字返回,但是在结果中它被强制为字符串。尽管仍然可以使用数字访问这些属性,因为使用方括号表示法也会将参数强制转换为字符串:

javascript 复制代码
console.log(peopleByAge[28]);
// => [{"name":"Alice","age":28}, {"name":"Eve","age":28}]
console.log(peopleByAge["28"]);
// => [{"name":"Alice","age":28}, {"name":"Eve","age":28}]

使用MAP.GROUPBY进行分组

GroupBy 所做的事情与 Object.groupBy 几乎相同,只是返回一个Map。这意味着您可以使用所有常用的 Map 函数。它还意味着可以从回调函数返回任何类型的值:

javascript 复制代码
const ceo = { name: "Jamie", age: 40, reportsTo: null };
const manager = { name: "Alice", age: 28, reportsTo: ceo };

const people = [
  ceo
  manager,
  { name: "Bob", age: 30, reportsTo: manager },
  { name: "Eve", age: 28, reportsTo: ceo },
];

const peopleByManager = Map.groupBy(people, (person) => person.reportsTo);

示例中,根据人们向谁报告进行分组。注意,要通过对象从这个 Map 检索项,对象必须具有相同的标识:

javascript 复制代码
peopleByManager.get(ceo);
// => [{ name: "Alice", age: 28, reportsTo: ceo }, { name: "Eve", age: 28, reportsTo: ceo }]
peopleByManager.get({ name: "Jamie", age: 40, reportsTo: null });
// => undefined

在上例中,使用了一个看起来像 ceo 对象的对象,但它不是同一个对象,因此它不会从 Map 返回任何内容。若要成功地从 Map 检索项,请确保使用要用作键的对象的引用。

何时可以使用GROUPBY方法

这两个 groupBy 方法目前处于TC39提案的第3阶段。这意味着它很有可能成为一个标准,因此会出现一些实现。

Chrome 117刚刚发布了对这两种方法的支持,Firefox Nightly在一个Flag后实现了它们。Safari 已经用不同的名称实现了这些方法,我相信它们很快就会更新。因为这些方法都在 Chrome 中,这意味着它们已经在 V8中实现了,所以下次 V8更新时 Node 中也会有这些方法。

为什么使用静态方法

您可能会思考这为什么作为 Object.groupBy 而不是 Array.Prototype.groupBy 实现的。根据提案,现在有一个库用一个不兼容的 groupBy 方法来给 Array.prototype打补丁。当考虑新的web API 时,向后兼容性非常重要的。几年前在一个名为 SmooshGate 的事件中,当试图实现 Array.Prototype.flatten 时,这一点就得到了强调。

幸运的是,使用静态方法实际上似乎更有利于将来的扩展性。当Records 和 Tuple 提案实现时,我们可以添加 Record.groupBy 方法,将数组分组到一个不可变的记录中。

JAVASCRIPT 正在填补空白

将元素分组到在一起显然是我们作为开发人员要做的一件重要的事情。lodash.groupBy目前在npm上的下载量高达150万到200万次。很高兴看到 JavaScript 正在填补这项空白,并使我们的工作更容易。

现在,去拿 Chrome117,自己试试这些新方法吧。

相关推荐
清灵xmf7 分钟前
TypeScript 类型进阶指南
javascript·typescript·泛型·t·infer
小白学大数据14 分钟前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
qq_3901617722 分钟前
防抖函数--应用场景及示例
前端·javascript
334554321 小时前
element动态表头合并表格
开发语言·javascript·ecmascript
John.liu_Test1 小时前
js下载excel示例demo
前端·javascript·excel
Yaml41 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事1 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶1 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo1 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx
理想不理想v1 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript