当前位置:首页 > 文章列表 > 文章 > 前端 > 如何利用 Generator 配合 yield* 实现对多维树形数组的非递归扁平化迭代

如何利用 Generator 配合 yield* 实现对多维树形数组的非递归扁平化迭代

2026-05-04 15:29:39 0浏览 收藏

积累知识,胜过积蓄金银!毕竟在文章开发的过程中,会遇到各种各样的问题,往往都是一些细节知识点还没有掌握好而导致的,因此基础知识点的积累是很重要的。下面本文《如何利用 Generator 配合 yield* 实现对多维树形数组的非递归扁平化迭代》,就带大家讲解一下知识点,若是你对本文感兴趣,或者是想搞懂其中某个知识点,就请你继续往下看吧~

Generator 配合 yield 实现的是递归式生成器、非递归式执行的扁平化迭代,利用暂停/恢复机制避免调用栈溢出,空间复杂度降为 O(d);yield 是委托语法,实现链式遍历,无需手动维护栈。

如何利用 Generator 配合 yield* 实现对多维树形数组的非递归扁平化迭代

Generator 配合 yield* 实现的“非递归扁平化迭代”,这个说法需要先厘清一个关键点:它本质仍是递归逻辑,但执行方式是非阻塞、按需迭代的。所谓“非递归”,指的是不依赖函数调用栈逐层展开(避免栈溢出),而是利用 Generator 的暂停/恢复机制 + 递归调用自身生成器,实现内存友好、流式产出的扁平化——准确说是递归式 Generator,非递归式执行

核心优势在于:不一次性构建完整结果数组,每次 next() 只计算并返回下一个值,空间复杂度从 O(n) 降至 O(d),d 为最大嵌套深度。

为什么 yield* 是关键

yield* 不是普通 yield,它是“委托”语法:把当前生成器的执行权,临时交给另一个可迭代对象(比如另一个 generator 函数)。当被委托的 generator 执行完毕,控制权自动交还。这使得嵌套结构的遍历天然形成链式调用,无需手动维护栈或队列。

标准实现(支持任意深度)

以下是一个简洁、健壮、符合现代 JS 规范的写法:

  • function* 声明生成器函数
  • 遍历输入数组,对每个元素判断是否为数组
  • 若是数组,用 yield* flat(item) 委托给自身处理
  • 若不是,直接 yield item

示例代码:

function* flat(arr) {
  for (const item of arr) {
    if (Array.isArray(item)) {
      yield* flat(item); // ← 关键:递归委托,不压栈,只挂起当前上下文
    } else {
      yield item;
    }
  }
}
<p>// 使用方式:可遍历、可转数组、可配合 for...of 或扩展运算符
const nested = [1, [2, [3, 4]], [5, [6, [7]]]];
const result = [...flat(nested)]; // [1, 2, 3, 4, 5, 6, 7]
</p>

如何避免常见陷阱

  • 不要混用 return 和 yield*:Generator 中 return 会立即终止,且其值不会被 yield* 捕获;确保所有分支都通过 yield 或 yield* 输出
  • 注意稀疏数组和空位for...of 会跳过空位(如 [1, , 3]),与 flat() 行为一致;若需保留索引位置,改用 for (let i = 0; i < arr.length; i++)
  • 类型安全判断优先用 Array.isArray(),而非 typeof item === 'object',后者会误判 null、Date、Object 等

进阶:带路径信息的扁平化(适用于树形配置)

如果原始数据是带 key 的树形结构(如菜单、分类、权限节点),你可能需要同时输出值和路径。这时可在递归调用时传递当前路径:

function* flatWithPath(obj, path = []) {
  if (Array.isArray(obj)) {
    for (let i = 0; i < obj.length; i++) {
      yield* flatWithPath(obj[i], [...path, i]);
    }
  } else if (obj && typeof obj === 'object') {
    for (const [key, value] of Object.entries(obj)) {
      yield* flatWithPath(value, [...path, key]);
    }
  } else {
    yield { value: obj, path };
  }
}

这样每项产出都是 { value, path },便于后续映射或调试。

到这里,我们也就讲完了《如何利用 Generator 配合 yield* 实现对多维树形数组的非递归扁平化迭代》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于的知识点!

财经类视频禁用哪些词汇_抖音财经内容违禁词与专业表达财经类视频禁用哪些词汇_抖音财经内容违禁词与专业表达
上一篇
财经类视频禁用哪些词汇_抖音财经内容违禁词与专业表达
如何解决 Win11 系统由于路径过长无法复制文件 突破 260 字符限制
下一篇
如何解决 Win11 系统由于路径过长无法复制文件 突破 260 字符限制
查看更多
最新文章