乐趣区

关于javascript:JavaScript-终于原生支持数组分组了

在日常开发中,很多时候须要对数组进行分组,每次都要手写一个分组函数,或者应用 lodash 的 groupBy 函数。好消息是,JavaScript 当初正在引入全新的分组办法:Object.groupByMap.groupBy,当前再也不须要手写分组函数了,目前最新版本的 Chrome(117)曾经反对了这两个办法!

以前的数组分组

假如有一个由示意人员的对象组成的数组,须要依照年龄进行分组。能够应用 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 上的任何属性或办法,例如 hasOwnPropertytoString等。尽管这样做能够防止意外笼罩 Object.prototype 上的属性,但也意味着不能应用一些与对象相干的办法。

const peopleByAge = Object.groupBy(people, (person) => person.age);

console.log(peopleByAge.hasOwnProperty("28"));

// TypeError: peopleByAge.hasOwnProperty is not a function

在调用 Object.groupBy 时,传递给它的回调函数应该返回一个字符串或 Symbol 类型的值。如果回调函数返回其余类型的值,它将被强制转换为字符串。

在这个例子中,回调函数返回的是一个数字类型的 age 属性值,但因为 Object.groupBy 办法要求键必须是字符串或 Symbol 类型,所以该数字会被强制转换为字符串类型。

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.groupByObject.groupBy 简直做的是雷同的事件,只是返回的后果类型不同。Map.groupBy返回一个 Map 对象,而不是像 Object.groupBy 返回一个一般的对象。、

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 中获取数据,那么要求这些对象具备雷同的身份或援用。这是因为 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 中的 ceo 对象不是同一个对象,所以无奈检索到对应的值。

浏览器反对

这两个 groupBy 办法是 proposal-array-grouping 提案提出的,该提案目前处于第 3 阶段,预计会在 2024 年成为正式规范。

9 月 12 日,Chrome 117 公布,该版本反对了这两个办法。Firefox Nightly 在一个标记后曾经实现了这两个办法。Safari 曾经以不同的名称实现了这些办法。因为这些办法在 Chrome 中可用,这意味着它们曾经在 V8 中被实现,所以下一次 V8 更新时它们将在 Node 中可用。

为什么要应用静态方法?

你可能会想,为什么这个性能被实现为 Object.groupBy 而不是 Array.prototype.groupBy。依据提案,有一个库已经用不兼容的groupBy 办法对 Array.prototype 进行了批改。在思考为 Web 新增 API 时,向后兼容性十分重要。几年前,在尝试实现 Array.prototype.flatten 时就呈现了一个称为 SmooshGate 的事件。

应用静态方法实际上对将来的可扩展性更好。当 RecordsTuples提案实现时,能够增加一个 Record.groupBy 办法,用于将数组分组为不可变记录。

简而言之,应用静态方法能够更好地放弃向后兼容性,并提供更好的扩展性,以便在将来增加更多功能和数据结构。

JavaScript 正在填补这些空白,并使咱们的开发更简略。目前,lodash.groupBy每周的 npm 下载量在 150 万至 200 万次之间,当所有浏览器都反对该办法之后,就不再须要引入lodash.groupBy 库了!

退出移动版