Appearance
2757. 生成循环数组的值
ts
function* cycleGenerator(
arr: number[],
startIndex: number
): Generator<number, void, number> {
const len = arr.length
let currentIndex = ((startIndex % len) + len) % len // 处理负的 startIndex
while (true) {
const jump = yield arr[currentIndex]
if (typeof jump === 'number') {
currentIndex = (((currentIndex + jump) % len) + len) % len
}
}
}yield 的双向通信
yield 不只是「产出值」,它还可以接收值。const jump = yield arr[currentIndex] 同时做了两件事:
- 产出
arr[currentIndex]给调用方 - 暂停,等待调用方通过
.next(value)传入值,赋给jump
如果调用方调的是 .next()(无参数),jump 为 undefined,索引不变——下次调用继续产出同一序列的下一个元素。如果调用方传入了数字,索引按 jump 跳转。
这是 Generator 和普通迭代器的关键区别:Generator 支持双向通信。
负数取模的处理
((startIndex % len) + len) % len 是 JavaScript 中处理负数取模的标准写法。JavaScript 的 % 对负数的行为是「余数」而非「模」——-1 % 5 返回 -1 而非 4。通过 ((x % n) + n) % n 确保结果始终在 [0, n-1] 范围内。
两次模运算对性能影响通常很小(len 不变),如果确实处在极热路径里,也可以先把 startIndex 预处理成正数:if (startIndex < 0) startIndex += Math.ceil(-startIndex / len) * len。
无限循环
while (true) 使这个 Generator 永远不会自行终止——调用方需要自己决定何时停止(通过 break 或 return 退出 for...of)。这符合「循环数组」的语义:数组是环形的,没有终点。
