← 中文资源

简体中文版本

带尺寸校验的数组分块

把数组或任意可迭代对象切成固定大小分块,严格校验尺寸,并提供惰性生成器版本。

阅读英文原文

功能说明

该示例把长列表按固定大小分组,用于批量请求、分页渲染、并发上传和 UI 网格布局。chunk 返回二维数组,最后一块可以不足尺寸;chunkLazy 接受任意可迭代对象,按需产出每一块,适合处理生成器、Set 或超大集合而无需一次性分配全部结果。空输入返回空数组,不会产生空块。

关键代码

两个入口共用 assertSize,要求尺寸为正整数,零、负数与小数都会抛 RangeError。chunk 以 size 为步长切片,slice 会复制元素,因此块内数组与原数组不共享结构。chunkLazy 是生成器函数,内部维护 bucket,装满即 yield 并换新数组,循环结束后若还有剩余则再产出一次。它只要求 Symbol.iterator,不依赖 length 或下标访问。

使用注意

参数校验在生成器首次 next 时才执行,因为生成器函数体是惰性的;若希望调用即时报错,应先手动校验或改用普通函数返回迭代器。chunk 的每个块都是新数组,但元素本身仍是浅引用,修改嵌套对象会同时影响原数据。尺寸过大不会报错,只会得到单个块。对无限迭代器使用 chunkLazy 时,调用方必须自行 break,否则循环永不结束。

验证方式

将长度十的数组按三块分组,断言得到四块且最后一块长度为一;空数组返回空数组;尺寸大于长度时返回单块;测试零、负数与 1.5 抛 RangeError;用 Set 和生成器作为 chunkLazy 输入,逐块收集并断言顺序与原序列一致;对非可迭代值断言 TypeError。

代码示例

function assertSize(size) {
  if (!Number.isInteger(size) || size < 1) {
    throw new RangeError("size must be a positive integer");
  }
}

export function chunk(array, size) {
  if (!Array.isArray(array)) throw new TypeError("array must be an array");
  assertSize(size);
  const chunks = [];
  for (let index = 0; index < array.length; index += size) {
    chunks.push(array.slice(index, index + size));
  }
  return chunks;
}

export function* chunkLazy(iterable, size) {
  assertSize(size);
  if (iterable === null || typeof iterable[Symbol.iterator] !== "function") {
    throw new TypeError("iterable must implement Symbol.iterator");
  }
  let bucket = [];
  for (const item of iterable) {
    bucket.push(item);
    if (bucket.length === size) {
      yield bucket;
      bucket = [];
    }
  }
  if (bucket.length > 0) yield bucket;
}