Lodash详解——数组分块_.chunk

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情 Lo友们大家好!

摘要

使用原生js对Lodash工具库方法进行解析并扩展,本文详细解析_.chunk的使用及背后原理,并扩展reduce和slice的使用

_.chunk的使用

Lodash 中文文档

_.chunk(array, [size=1])

将数组(array)拆分成多个 size 长度的区块,并将这些区块组成一个新数组。 如果array 无法被分割成全部等长的区块,那么最后剩余的元素将组成一个区块。

参数

  1. array  (Array) : 需要处理的数组
  2. [size=1]  (number) : 每个数组区块的长度

返回

(Array) : 返回一个包含拆分区块的新数组(注:相当于一个二维数组)。

以上是Lodash_.chunk的使用方法,以下是原生实现:

const chunk = (arr, size) => { // 同样传入需要处理的数组和想要的数组区块长度
  return arr.reduce((previousValue, currentValue, currentIndex, array) => { // 使用reduce进行数组遍历
    return index % size === 0 // 根据数组长度判断是否分块
      ? [...previousValue, [currentValue]] // 将当前currentValue单独分块
      : [...previousValue.slice(0, -1), [...previousValue.slice(-1)[0], currentValue]] // 合并区块,只将currentValue放到最后一个区块
  }, [])
};

以上注释可能有些生涩,我们再来逐行讲解,这里指的区块是二维数组中的元素,其实就是个数组。 举个例子:

chunk(['A', 'B', 'C', 'D', 'E', 'F', 'G'], 3)
// result [['A', 'B', 'C'], ['D', 'E', 'F'], ['G']]

先简单介绍一下所用到的方法,已了解也可温习一下

  1. reduce((previousValue, currentValue, currentIndex, array) => {/* … */}, initialValue)
  • previousValue: 上一次调用箭头函数时的返回值。在第一次调用时,若指定了初始值initialValue,其值则为 initialValue,否则为数组索引为 0 的元素 array[0]
  • currentValue: 数组中正在处理的元素。在第一次调用时,若指定了初始值 initialValue,其值则为数组索引为 0 的元素 array[0],否则为 array[1]
  • currentIndex: 数组中正在处理的元素的索引。若指定了初始值 initialValue,则起始索引号为 0,否则从索引 1 起始。
  • array: 用于遍历的数组。
  1. slice(start, end)
  • start(可选):提取起始处的索引(从 0 开始),从该索引开始提取原数组元素。如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取,slice(-2) 表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)。如果省略 start,则 slice 从索引 0 开始。如果 start 超出原数组的索引范围,则会返回空数组。
  • end(可选): 提取终止处的索引(从 0 开始),在该索引处结束提取原数组元素。slice 会提取原数组中索引从 start 到 end 的所有元素(包含 start,但不包含 end)。slice(1,4) 会提取原数组中从第二个元素开始一直到第四个元素的所有元素(索引为 1, 2, 3 的元素)。如果该参数为负数,则它表示在原数组中的倒数第几个元素结束抽取。 slice(-2,-1) 表示抽取了原数组中的倒数第二个元素到最后一个元素(不包含最后一个元素,也就是只有倒数第二个元素)。如果 end 被省略,则 slice 会一直提取到原数组末尾。如果 start 大于数组的长度,slice 也会一直提取到原数组末尾。

接下来我们解析一下以下三行代码究竟做了什么

return index % size === 0 
    ? [...previousValue, [currentValue]] 
    : [...previousValue.slice(0, -1), [...previousValue.slice(-1)[0], currentValue]]

第一行通过下标对size取余,判断二维数组中是否已经有满足长度size的区块(数组),如果当前previousValue(二维数组)内已经有长度为size的倍数的区块(数组),执行第二行,否则,执行第三行

先看第三行,previousValue.slice(0, -1)抽取二维数组中除了最后一个数组的所有数组,并通过扩展运算符将所有数组取出来;如果previousValue中只有一个数组,previousValue.slice(0, -1)返回的就是[]

previousValue.slice(-1)[0]就是抽取二维数组中最后一个数组并取出数组,通过扩展运算符将数组中的值取出来与currentValue合并成一个新的数组元素,即[...previousValue.slice(-1)[0], currentValue];

第三行的意思就是,将当前正在处理的元素添加到二维数组中最后一个数组里面

回到第二行,如果index % size === 0,说明二维数组中已经有满足长度为size的区块了,所以只需要将当前currentValue放到一个新的数组区块里面。

第二行的意思就是,将当前正在处理的元素添加到二维数组中新建一个数组里面

所以,整体的逻辑出来了。这里不做例子输出展示,留给大家自己打开F12在控制台中尝试一下,因为可能你只是眼睛懂了

扩展阅读

You-Dont-Need-Lodash-Underscore本篇文章源码主要参考自此

25个你不得不知道的数组reduce高级用法这篇文章写的很全,我就引用一下吧

小结

用最啰嗦的言语解析每行代码,力求人人都能看懂,持续更新Lodash的100多个工具方法的使用和实现,一起学习,一起进步

~( ̄︶ ̄)↗点赞