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.
On this page

Example

#
JavaScript
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())
Console
{ value: 'Video', done: false }
{ value: 'Theory', done: false }
{ value: 'Quiz', done: false }
{ value: undefined, done: true }

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

#
Syntax
function* name(params) {
  yield value
  yield* iterable
  return finalValue
}

const generator = name()
generator.next()

More examples

#
A generator in a for...of loop and in a spread
JavaScript
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)])
Console
Level 1
Level 2
Level 3
[0, 5, 10, 15, 20]
An infinite sequence of ids
JavaScript
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)
Console
task-1
task-2
task-3

The while (true) loop doesn’t freeze the program, because the generator pauses at every yield and waits for the next call to next().

Combining generators with yield*
JavaScript
function* frontend() {
  yield 'HTML'
  yield 'CSS'
}

function* fullStack() {
  yield* frontend()
  yield 'JavaScript'
  yield* ['Node.js', 'SQL']
}

console.log([...fullStack()])
Console
['HTML', 'CSS', 'JavaScript', 'Node.js', 'SQL']

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 return has done: true, so a for...of loop and spread skip it. Anything that should end up in the result needs to go through yield.
  • Don’t spread or Array.from() an infinite generator. Pull values from it with next(), or break out of the loop with break.

Related entries

#

Spotted a mistake or missing an example? Write to us.