function*
JavaScript
generator function/生成器函式
function* - JavaScript | MDN
ジェネレータ - JavaScript.info
2024-11-19 JavaScriptのイテレータ, イテラブル, ジェネレータを理解する! | GMOインターネット アドエンジニア TECH BLOG byGMO
迭代器/Iterator
「可產生有限個/無限個值的物件」
擁有帶有0或1個參數的next方法
next方法回傳IteratorResult
IteratorResult:done+value
code:js
let n = 0
const iterator = {
next() {
n+=1
if (n>3) return { value: undefined, done: true }
return { value: n, done: false }
}
}
iterator().next() // { "value": 1, "done": false }
iterator().next() // { "value": 2, "done": false }
iterator().next() // { "value": 3, "done": false }
iterator().next() // { "value": undefined, "done": true }
iterator().next() // { "value": undefined, "done": true }
可迭代/Iterable
滿足迭代器的物件
擁有帶有0個參數的[Symbol.iterator]方法
[Symbol.iterator]方法回傳迭代器物件
即自行宣告且定義[Symbol.iterator]後,即可讓該物件可迭代
String、Array、Map、Set…等物件都是預設上可迭代
code:js
// 延續上例
const iterable = {};
iterableSymbol.iterator = () => {
return iterator
};
for (const i of iterable) {
console.log(i);
}
生成器/Generator
同時為迭代器且可迭代的物件
擁有回傳IteratorResult的next方法
擁有回傳迭代器的[Symbol.iterator]方法
即在[Symbol.iterator]中回傳自身
code:js
const generator = {
next() {
n+=1
if (n>3) return { value: undefined, done: true }
return { value: n, done: false }
},
Symbol.iterator() {
return this // 回傳自身
}
}
for (const g of generator) {
console.log(g);
}
生成器函式/Generator Function
使用function* ()宣告、搭配yield
函式本身回傳一生成器物件
呼叫next方法會回傳yield後方的值
code:js
const foo = function* () {
yield 1
yield 2
yield 3
}
const g = foo()
console.log(g) // object Generator
console.log(g.next()) // Object { value: 1, done: false }
console.log(g.next()) // Object { value: 2, done: false }
console.log(g.next()) // Object { value: 3, done: false }
console.log(g.next()) // Object { value: undefined, done: true }
let sum = 0
for (const gn of foo()) sum += g
console.log(sum) // 6
yield會暫時停止函式執行,並回傳繼續執行用的呼叫值
左值 = yield[值]
左值可省略
傳入next方式的參數,即為繼續執行時,代入左值用的值
生成器函式也存在return方法,用於結束生成器執行時
yield*可傳入可迭代的物件,並對其進行反覆處理
會呼叫傳入物件的[Symbol.iterator],取得迭代器
呼叫產生器的next方法時,會呼叫yield*取得的迭代器的next方法,回傳IteratorResult
非同步生成器函式
code:js
function delayedValue(time, value) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(value), time)
})
}
async function* generate() {
yield await delayedValue(1000, 1)
yield await delayedValue(100, 2)
yield await delayedValue(500, 3)
yield await delayedValue(250, 4)
yield await delayedValue(125, 5)
console.log("All done!")
}
async function main() {
for await (const value of generate()) {
console.log("value", value)
}
}
main().catch((e) => console.error(e))
生成器只會消費必要的記憶體
例如比較使用十萬個元素以上的陣列時,生成器能夠維持使用同樣的記憶體用量
實作:計數器
code:javascript
function* counter(startNum) {
for (let i=startNum; true; i++) yield i;
}
let gen = counter(5);
console.log(gen.next().value) // 5
console.log(gen.next().value) // 6
console.log(gen.next().value) // 7
從startNum開始,隨著呼叫next()不斷增加
generators let your function return multiple values.
not necessarily immediately -- the caller decides when to ask for the next one.
useful to describe operations where you can "ask for more",
like processing a long list or deciding each next setp based on user input