yield仅在function生成器函数中有效,配合迭代器协议通过next()控制暂停/恢复执行,返回{value, done}对象;不可用于普通、箭头或async函数(除非async function);自动生成[Symbol.iterator],支持for...of等语法糖。
JavaScript 中的 yield 关键字本身不“工作”,它只在 function*(生成器函数)内部起作用,且必须配合迭代器协议才能产生实际效果。
调用 function* 不会立即运行函数体,而是返回一个实现了 next() 方法的迭代器对象。每次调用 iterator.next(),函数才从上次暂停处继续执行,直到下一个 yield 或 return。
yield 表达式会暂停执行,并把右侧值作为 { value: ..., done: false } 的 value 返回next() 时,函数从 yield 后恢复,上一次 yield 表达式的返回值是本次 next(arg) 传入的 arg
return 时,done 变为 true,value 是返回值(或 undefined)function* countdown(n) {
while (n > 0) {
yield n;
n--;
}
return 'done';
}
const iter = countdown(3);
console.log(iter.next()); // { value: 3, done: false }
console.log(iter.next()); // { value: 2, done: false }
console.log(iter.next()); // { value: 1, done: false }
console.log(iter.next()); // { value: 'done', done: true }
yield 不能出现在普通函数、箭头函数或异步函数中语法错误会直接抛出 SyntaxError,比如在 async function 里写 yield,或在 () => { yield 1; } 中使用——这些都不合法。
function* 内部允许 yield
async function* 是合法的,它返回异步迭代器,yield 仍可用,但需配合 for await...of 或 next().then()
yield 后面可以是任意表达式,包括 yield* anotherGenerator()(委托迭代)for...of 和展开运算符依赖它for...of、[...iter]、Array.from(iter) 等语法糖,本质都是反复调用 iter.next(),直到 done: true。如果对象没有 [Symbol.iterator]() 方法,就会报错 TypeError: XXX is not iterable。
[Symbol.iterator],所以可直接用于 for...of
next() 的对象,yield 是最简方式,否则要自己维护状态和 done 标志done: true,后续所有 next() 调用都返回 { value: undefined, done: true },不可重用function* fib() {
let [a, b] = [0, 1];
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const fibIter = fib();
console.log(fibIter.next().value); // 0
console.log(fibIter.next().value); /
/ 1
console.log(fibIter.next().value); // 1
console.log(fibIter.next().value); // 2
// 可无限遍历(但注意别用 [...fib()],会卡死)
for (const n of fib()) {
if (n > 10) break;
console.log(n); // 0 1 1 2 3 5 8
}
真正容易被忽略的是:生成器函数内部的 try...finally 在 return 或 throw 时仍会执行,但 yield 暂停期间不会触发;另外,yield 表达式本身有返回值,这个值只在下一次 next(arg) 时传入,不是 yield 右侧表达式的值。