手动调用next()指脱离for...of自动调度、显式参与流程决策,典型场景包括成对消费、提前终止后继续、双迭代器协同、带缓冲解析;识别特征为解构调用、while循环、多分支分别调用等。

识别迭代器 next() 的手动调用,关键不是看“有没有写 next()”,而是看它是否脱离了 for...of 或 for 循环的自动调度,被嵌入到条件判断、跳转控制、多路分支或状态协同等逻辑中。这类场景下,next() 不再是隐式驱动,而是显式参与流程决策。
需要手动步进的典型场景
当遍历不能线性平铺,而需依据当前值做动态决策时,自动循环就不再适用:
-
成对/分组消费:比如把数组 [a,b,c,d] 每两个元素一组处理(a&b、c&d),用
for...of无法跳过下一个;必须手动调两次next()并检查done -
提前终止+保留位置:查找首个满足条件的元素后,不结束整个遍历,而是从下一个位置继续处理剩余项——这要求你拿到匹配项后,再调一次
next()获取后续起点 -
双迭代器协同:例如合并两个已排序数组,需根据两者的当前值比较决定谁推进,此时两个迭代器各自独立调用
next(),由业务逻辑协调节奏 -
带缓冲的解析器:如解析 CSV 行或协议帧,常需“预读”一行判断类型,若不符合预期则回退逻辑上不推进,但物理上
next()已执行——这时必须靠返回的{value, done}显式管理状态,而非依赖循环结构
一眼识别手动调用的代码特征
以下模式出现任意一项,基本可判定为手动控制:
- 直接解构
const { value, done } = it.next(),并用if (!done)包裹后续逻辑 - 在
while或do...while中反复调用next(),且循环条件含!it.next().done类写法(注意:这种写法有副作用,不推荐) - 同一迭代器变量在多个
if/else分支中分别调用next(),例如:if (cond) it.next(); else { x = it.next().value; } - 将
next()结果赋给不同变量用于比对或暂存,如const a = it.next(); const b = it.next(); process(a.value, b.value);
容易误判的边界情况
有些写法看似手动,实则仍是自动循环的变体,需注意区分:
-
for (const x of arr) { if (x > 10) continue; doSomething(x); }—— 这仍是for...of自动驱动,continue只影响本次循环体,不干预迭代器本身 -
Array.from(iterator, x => x * 2)或[...it]—— 展开操作内部调用next(),但对外不可见,不属于“手动调用” - 用
next(it)封装函数但只调一次,且不检查done—— 属于取首项快捷写法,不算复杂步进逻辑
为什么必须明确识别?
因为手动调用会绕过语言层的遍历契约,带来三类风险:
- 状态漂移:同一个迭代器在
for...of和手动next()间混用,会导致漏项或越界 - 空数组陷阱:空迭代器首次
next()即{ value: undefined, done: true },若代码假设value存在,就会出错 - 不可重置性:手动推进后无法“倒带”,要重来只能重新调用
arr[Symbol.iterator]()











