lodash源码分析之chunk的尺与刀

以不正义开始的事情,必须用罪恶使它巩固。 ——莎士比亚《麦克白》

最近很多事似乎印证了这句话,一句谎言最后要用一百句谎言来圆谎。

本文为读 lodash 源码的第二篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash

gitbook也会同步仓库的更新,gitbook地址:pocket-lodash

作用与用法

chunk 函数可以将一个数组,切割成指定大小的块,返回由这些块组成的新数组。

chunk 函数在前端可以用来缓解一些性能问题。例如大量的 DOM 操作,可以分块让浏览器在空闲的时候处理,避免页面卡死。如下面的代码,向页面中插入大量的DOM。

const arr = [] // 1万条数据
const chunks = _.chunk(arr, 100)

const append = function () {
  if (chunks.length > 0) {
    const current = chunks.pop()
    current.forEach(item => {
      const node = document.createElement('div')
      node.innerText = item
      document.body.appendChild(node)
    })
    setTimeout(append, 0)
  }
}

append()

依赖

import slice from './slice.js'

读lodash源码之从slice看稀疏数组与密集数组

原理

chunk 的原理归结起来就是切割和放置。

chunk 最后返回的结果如 [[1],[1],[1]] 的形式,放置就是将切割下来的块放置到数组容器中。

那要怎样切割呢?

因为指定了大小,因此切割跟切蛋糕很像,参数 size 是尺子,测好每块的长度,slice 函数是刀, 将数组一块一块切出来。

例如有 [1,2,3,4,5] 这个数组,size 指定为 2,则第一次切割会得到 [1,2] 的块,第二次切割得到 [4,5],剩下的是 [5] 。这个数组最终会被切为三块。

明白了原理,下面来看看源码。

源码总览

function chunk(array, size) {
  size = Math.max(size, 0)
  const length = array == null ? 0 : array.length
  if (!length || size < 1) {
    return []
  }
  let index = 0
  let resIndex = 0
  const result = new Array(Math.ceil(length / size))

  while (index < length) {
    result[resIndex++] = slice(array, index, (index += size))
  }
  return result
}

参数处理

size = Math.max(size, 0)
const length = array == null ? 0 : array.length
if (!length || size < 1) {
  return []
}

确保 length 存在和 size1 大,如果不满足条件,返回空数组。

在切割之前,需要用尺确定切割的数量。

从上面的原理分析可以看到,切割是不公平的,除了前面的块都是等分外,最后一块可能会比前面的少。

那怎么确定切割的数量呢?学过除法的知道, length/size 即可知道平均分块的数量,如果有余数,则余数是最后那块的长度,需要向上取整。

这在 javascript 中可以用 Math.ceil 函数,它返回的是向上取整后的结果。

看下代码:

const result = new Array(Math.ceil(length / size))

这里创建了一个用来放置所有块的容器 result 。容器的长度刚好与块的数量一致。

let index = 0
let resIndex = 0
while (index < length) {
  result[resIndex++] = slice(array, index, (index += size))
}

测量好块的数量后,就要下刀切割啦。每切割下一块,就立马放置到容器 result 中。

index 是放置块的位置,resIndex 是切割的开始位置。

index 与块的数量 length 相等时,表示已经切割完毕,停止切割,最后将结果返回。

参考

  1. lodash源码解析——chunk函数

License

署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)

作者:对角另一面

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序人生 阅读快乐

JavaScript函数式编程

JavaScript 是近年来非常受瞩目的一门编程语言,它既支持面向对象编程,也支持函数式编程。本书专门介绍JavaScript函数式编程的特性。

442
来自专栏顶级程序员

关于Java面试,你应该准备这些知识点

来自:简书 占小狼 链接:http://www.jianshu.com/p/1b2f63a45476(点击尾部阅读原文前往) 链接:http://www.ji...

3366
来自专栏java工会

从零讲JAVA ,给你一条清晰地学习道路!该学什么就学什么!!

1567
来自专栏Java架构

阿里面试题一面:(电话面试:80分32秒)二面: (视频面试:47分钟)三面:(视频面试:22分钟)四面:(交叉面,电话面试:30分钟)

5883
来自专栏java思维导图

从零讲JAVA ,给你一条清晰地学习道路!该学什么就学什么!!

主要学习: 1.向量,链表,栈,队列和堆,词典。熟悉 2.树,二叉搜索树。熟悉 3.图,有向图,无向图,基本概念 4.二叉搜索A,B,C类熟练,9大排序熟悉。 ...

1125
来自专栏程序员互动联盟

【面试宝典】Java如何打印数组

面试官: 如何打印一个数组? 小白:用for循环。 面试官:如何打印一个List? 小白:用for循环。 面试官:如果打印一个二维数组? 小白:还是for循环。...

3469
来自专栏刘笑江的专栏

notes-on-7-concurrency-model-in-7-weeks

1513
来自专栏破晓之歌

JAVA入门3-2(未完,待续) 原

List(序列)、Queue(队列)可重复排列有序的,Set(集)不可重复无序。list和set常用。

895
来自专栏程序员互动联盟

【面试宝典】Java之线程一如何开启线程

面试官:大四是吧? 小白:是的,学校大四没有课,只有毕业设计,就想着提前出来锻炼锻炼。 面试官:想法很好,那咱们开始吧,知道线程吧! 小白:嗯,线程是CPU执行...

31811
来自专栏包子铺里聊IT

电面基础:Java基于Map/Hashtable的问题讨论

电面基础:Java基于Map/Hashtable的问题讨论 前言:电话面试(简称电面)以知识点考察为主,在数据结构方面,对于Map/Hashtable的考察绝对...

3167

扫码关注云+社区