JavaScript 的新数组分组方法
对数组中的项目进行分组,你可能已经做过很多次了。每次都会手动编写一个分组函数,或者使用 lodash 的 groupBy 函数。
好消息是,JavaScript 现在有了分组方法,所以你再也不必这样做了。Object.groupBy 和 Map.groupBy 这两个新方法将使分组变得更简单,并节省我们的时间或依赖性。
以前的做法
假设你有一个代表人的对象数组,你想按年龄对它们进行分组。你可以这样使用 forEach 循环:
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:
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 方法,你就可以像这样得出结果:
const peopleByAge = Object.groupBy(people, (person) => person.age);
简单多了!不过也有一些需要注意的地方。
Object.groupBy 返回一个空原型对象。这意味着该对象不继承 Object.prototype 的任何属性。这很好,因为这意味着你不会意外覆盖 Object.prototype 上的任何属性,但这也意味着该对象没有你可能期望的任何方法,如 hasOwnProperty 或 toString。
const peopleByAge = Object.groupBy(people, (person) => person.age);
console.log(peopleByAge.hasOwnProperty("28"));
// TypeError: peopleByAge.hasOwnProperty is not a function
传递给 Object.groupBy 的回调函数应返回字符串或Symbol。如果返回其他内容,则将强制转为字符串。
在我们的示例中,我们一直以数字形式返回age,但在结果中却被强制转为字符串。尽管如此,你仍然可以使用数字访问属性,因为使用方括号符号也会将参数强制为字符串。
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
除了返回 Map 之外,Map.groupBy 的功能与 Object.groupBy 几乎相同。这意味着你可以使用所有常用的 Map 函数。这也意味着你可以从回调函数返回任何类型的值。
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 中按对象检索项目,对象必须具有相同的引用。
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 方法是 TC39 提议的一部分,目前处于第三阶段。这意味着它很有可能成为一项标准,因此也出现了一些实施方案。
Chrome 浏览器 117 版本刚刚推出了对这两种方法的支持,而 Firefox 浏览器 119 版本也发布了对这两种方法的支持。Safari 以不同的名称实现了这些方法,我相信他们很快就会更新。既然 Chrome 浏览器中出现了这些方法,就意味着它们已在 V8 中实现,因此下次 V8 更新时,Node 中也会出现这些方法。
为什么使用静态方法
你可能会问,为什么要以 Object.groupBy 而不是 Array.prototype.groupBy 的形式来实现呢?根据该提案,有一个库曾经用一个不兼容的 groupBy 方法对 Array.prototype 进行了猴子补丁。在考虑新的应用程序接口时,向后兼容性非常重要。几年前,在尝试实现 Array.prototype.flatten 时,这一点在一次被称为 SmooshGate 的事件中得到了强调。
幸运的是,使用静态方法似乎更有利于未来的可扩展性。当 Record 和 Tuples 提议实现时,我们可以添加一个 Record.groupBy 方法,用于将数组分组为不可变的记录。
总结
将项目分组显然是我们开发人员的一项重要工作。目前,每周从 npm 下载 lodash.groupBy 的次数在 150 万到 200 万之间。很高兴看到 JavaScript 填补了这些空白,让我们的工作变得更加轻松。
现在,下载 Chrome 117 并亲自尝试这些新方法吧。
JavaScript 的新数组分组方法的更多相关文章
- JavaScript中的数组Array方法
push(),pop()方法 push(),pop()方法也叫栈方法,push()可以理解成,向末尾推入,而pop()恰好相反,可以理解成从末尾移除(取得). var nums=[1,2,3,4]; ...
- javascript 克隆对象/数组的方法 clone()
1 11 javascript 克隆对象/数组的方法 clone() 1 demo: code: 1 var Obj; 2 let clone = (Obj) => { 3 var buf; ...
- javascript常见操作数组的方法
在 JavaScript 中,判断一个变量的类型尝尝会用 typeof 运算符,在使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回 "obj ...
- JavaScript中操作数组的方法
JavaScript Array 对象 对数组操作的方法分为两种 一种是会改变原始数组的变异方法,还有一种是不会改变原始数组的非变异方法. 总结 巧记 Push() 尾部添加 pop() 尾部删除 U ...
- JavaScript中Array数组的方法
查找: indexOf.lastIndexOf 迭代:every.filter.forEach.map.somereduce.reduceRight 用法: /* 1 查找方法: * arr.inde ...
- js中实现截取数组的后几个元素作为一个新数组的方法
有时候我们会遇到这种需求,截取数组中后5个元素作为一个新数组,且顺序不能变.数组中的slice()方法和splice()方法都可以实现这样的操作. const arr = [1,2,7,2,6,0,3 ...
- javaScript中的数组迭代方法
ECMAScript5为数组定义了5个迭代方法. 每个方法都接收两个参数:要在每一项上运行的函数 和 (可选的)运行该函数的作用域对象. 传入这些方法中的函数会接收三个参数:数组项的值,该项在数组 ...
- JavaScript中对象数组去重方法
在一次对后端返回的对象数组的操作时想通过indexOf()或者includes()的方法来实现对对象数组的去重但是行不通,因为用indexOf()返回的都是-1,一下记录两种对象数组(更具指定属性)去 ...
- javascript打开新页面的方法
方案一: A标签: 这里要注意target的设置,_Blank是指新窗口,也可以用js来模拟创建. <a href="http://www.cnblogs.com" targ ...
- es5和es6创建新数组的方法
//es5 let array = Array(5) let array = [] //es6 1.let array = Array.of(1,2,3,4,5) 2.let array = Arra ...
随机推荐
- MySQL 8.2.0部署安装验证
MySQL 8.2.0部署安装验证 背景 昨天捯饬了半天Oracle23c Free版本发现自己白忙活了. 然后想着继续看一下 MySQL8.2. 看看会不会又继续白忙活 下载与安装 https:// ...
- Redis监控方法之二
Redis监控方法之二 背景 前期整理过使用 exporter + prometheus 方式进行Redis监控的搭建过程 最近给同事研究clickhouse时发现 clickhouse 有对应的pl ...
- [转帖]Oracle迁移到MySQL时数据类型转换问题
https://www.cnblogs.com/yeyuzhuanjia/p/17431979.html 最近在做"去O"(去除Oracle数据库)的相关工作,需要将Oracle表 ...
- [转帖]使用s3(minio)为kubernetes提供pv存储
http://www.lishuai.fun/2021/12/31/k8s-pv-s3/#/%E8%A6%81%E6%B1%82 我们可以通过csi使用s3为kubernetes提供pv存储,当我们申 ...
- [转帖]Kafka 核心技术与实战学习笔记(六)kafka线上集群部署方案
一.操作系统-Linux Kafka是JVM系的大数据框架 kafka由Scala语言和Java语言编写而成,编译之后的源代码就是普通的".class"文件 使用Linux kaf ...
- STM32CubeMX教程24 WDG - 独立窗口看门狗
1.准备材料 开发板(正点原子stm32f407探索者开发板V2.4) STM32CubeMX软件(Version 6.10.0) 野火DAP仿真器 keil µVision5 IDE(MDK-Arm ...
- API架构风格对比:SOAP vs REST vs GraphQL vs RPC
API架构风格对比:SOAP vs REST vs GraphQL vs RPC 最近一段时间关于GraphQL的讨论很多,一些项目中也相继用到了这种风格,但使用是否合理,是否存在杀鸡用牛刀这样的问题 ...
- HarmonyOS实战[一]——原理概念介绍安装:基础篇
[本文正在参与"有奖征文|HarmoneyOS征文大赛"活动] 相关文章: HarmonyOS实战[一]--原理概念介绍安装:基础篇 HarmonyOS实战[二]-超级详细的原子化 ...
- 【操作系统和计网从入门到深入】(四)基础IO和文件系统
前言 这个专栏其实是博主在复习操作系统和计算机网络时候的笔记,所以如果是博主比较熟悉的知识点,博主可能就直接跳过了,但是所有重要的知识点,在这个专栏里面都会提到!而且我也一定会保证这个专栏知识点的完整 ...
- 【STL源码剖析】string类模拟实现 了解底层-走进底层-掌握底层【超详细的注释和解释】
文章目录 博主对大家的话 前言 实现过程一些要注意的点 STL中string类模拟实现 尾声 博主对大家的话 从今天开始,STL源码剖析的专栏就正式上线了!其实在很多人学习C++过程中,都是只学习一些 ...