function*
Declares a generator: a function that hands back successive values through yield and pauses between them.
- Returns
- Calling a generator function returns a generator object, which is both an iterator and an iterable.
Example
#function* lessonSteps() {
yield 'Video'
yield 'Theory'
yield 'Quiz'
}
const steps = lessonSteps()
console.log(steps.next())
console.log(steps.next())
console.log(steps.next())
console.log(steps.next())Definition and usage
#A function written as function* is a generator. Calling it doesn’t run the code right away, it returns a generator object instead. The code only starts after you call next(), and runs up to the nearest yield, which hands back a value and pauses the function right there. The next next() resumes work exactly where it left off.
Every next() returns an object { value, done }. As long as the generator keeps reaching further yields, done is false. Once the function finishes, or hits a return, you get done: true. A generator is an iterable object, so you can walk it with a for...of loop, spread it with [...gen], or pass it to Array.from().
Generators compute values lazily, meaning only once they’re needed. That lets them describe even infinite sequences, like successive ids, without using up memory. yield* forwards every value from another iterable, and async function* creates an async generator, which you walk with a for await...of loop.
Syntax
#function* name(params) {
yield value
yield* iterable
return finalValue
}
const generator = name()
generator.next()More examples
#function* range(start, end, step = 1) {
for (let i = start; i <= end; i += step) {
yield i
}
}
for (const level of range(1, 3)) {
console.log(`Level ${level}`)
}
console.log([...range(0, 20, 5)])function* createIds(prefix) {
let id = 1
while (true) {
yield `${prefix}-${id}`
id++
}
}
const taskIds = createIds('task')
console.log(taskIds.next().value)
console.log(taskIds.next().value)
console.log(taskIds.next().value)The while (true) loop doesn’t freeze the program, because the generator pauses at every yield and waits for the next call to next().
function* frontend() {
yield 'HTML'
yield 'CSS'
}
function* fullStack() {
yield* frontend()
yield 'JavaScript'
yield* ['Node.js', 'SQL']
}
console.log([...fullStack()])Browser support
#Widely available
Works in all modern browsers, phones included. You can use it without worry.
- Chrome
- Edge
- Firefox
- Safari
Good practices
#- You can only walk a generator once. When you need the values again, call the generator function again, or save the results into an array.
- The value from
returnhasdone: true, so afor...ofloop and spread skip it. Anything that should end up in the result needs to go throughyield. - Don’t spread or
Array.from()an infinite generator. Pull values from it withnext(), or break out of the loop withbreak.
Related entries
#- Iterators (Symbol.iterator)The iteration protocol: an object with a [Symbol.iterator]() method works with for...of, spread, and destructuring.
- for...ofWalks the successive values of an iterable object: an array, a string, a Map, a Set, and others.
- functionDeclares a named function: a block of code with parameters that you can call any number of times and that can return a result.
- Spread (...)The spread syntax spreads an array, string, or object out into individual elements: for copying, merging, and passing arguments.
- returnEnds a function and passes a value back to the place where the function was called.
Spotted a mistake or missing an example? Write to us.