代码

  1. groupByWith(array, key) {
  2. return array.reduce(function (accumulator, currentValue) {
  3. (accumulator[currentValue[key]] = accumulator[currentValue[key]] || []).push(currentValue);
  4. return accumulator;
  5. }, {});
  6. }

这段代码的作用是按属性值对 object 数组分组

分析

先阅读此文了解 reduce 函数的概念和常规用法。
reduce
看完上面的文章,就会知道按属性对 object 数组进行分类,不过是文章中举例出来的最常规的用法之一而已。
然后我们再看,他的代码和 MDN 中的示例代码有啥区别,其实逻辑上没有任何区别,只是他的代码更加精简,看起来很紧凑、很酷而已。

我相信, reduce 没啥好说的了,他这里给 reduce 提供了一个初始值 {},通过了解 callback 首次执行的逻辑,我们知道提供了初始值的逻辑为:

  • accumulator = initialValue(提供的初始值)
  • currentValue = array[0] (源数组中索引为 0 的项)

即因为提供了初始值,所以 reduce 从索引为 0 的地方开始执行 callback 方法

最后一眼望去,最看不懂的地方其实就是第 3 行代码,因为写的过于紧凑,导致看起来很懵逼,但其实也就那么回事,我们拆分一下这句代码,并配合一段 JSON 数据来做解释:

  1. [
  2. {
  3. name: '张三',
  4. department: '部门A'
  5. },
  6. {
  7. name: '李四',
  8. department: '部门A'
  9. },
  10. {
  11. name: '张三',
  12. department: '部门B'
  13. },
  14. ]
  1. (accumulator[currentValue[key]] = accumulator[currentValue[key]] || [])
    • currentValue[key]: 首次 currenValue 就是 { name: ‘张三’, department: ‘部门A’ }key 假设外面传递进来的是 name,那 这句代码最后就得出 张三 这个字符串
    • accumulator[currentValue[key]]:首次循环,我们知道 accumulator = initialValue,所以这里其实就是往累计器中增加了一个属性,key张三,所以这一步仅仅是动态计算属性名然后添加到对象中
    • = accumulator[currentValue[key]] || []:这句话分为左右两部分,因为使用了 || ,那么我们就知道如果 || 左边的表达式计算出来的结果没有值,就会用右边的值,如果左边有值,就不会用右边的值。

那我们就可以带入来思考一下 accumulator[currentValue[key]] 的结果是什么,就是取 accumulator 对象中某个属性的值啊,即 accumulator[‘张三’],所以这里取的是 key张三value,所以如果 accumulator 中已经有张三,就要拿到张三的的值(数组),如果没有张三,就声明一个空数组,这样做的意义是什么呢?因为后续我们需要往这个数组里面 push 东西啊。

简单解释一下就是:如果有张三,就先得到张三的值(值为数组),然后往已有的这个值(数组)里面 push 东西,如果没有就声明一个空数组。

  1. .push(currentValue);

将上一步得到的数组作为基础,然后调用 .push(currentValue) 往其中新增项