function*

Deklaruje generator: funkcję, która oddaje kolejne wartości przez yield i wstrzymuje się między nimi.

Zwraca
Wywołanie funkcji generatora zwraca obiekt generatora, który jest jednocześnie iteratorem i obiektem iterowalnym.
Na tej stronie

Przykład

#
JavaScript
function* lessonSteps() {
  yield 'Wideo'
  yield 'Teoria'
  yield 'Quiz'
}

const steps = lessonSteps()

console.log(steps.next())
console.log(steps.next())
console.log(steps.next())
console.log(steps.next())
Konsola
{ value: 'Wideo', done: false }
{ value: 'Teoria', done: false }
{ value: 'Quiz', done: false }
{ value: undefined, done: true }

Definicja i zastosowanie

#

Funkcja zapisana jako function* jest generatorem. Jej wywołanie nie uruchamia kodu od razu, tylko zwraca obiekt generatora. Kod rusza dopiero po wywołaniu next() i działa do najbliższego yield, które oddaje wartość i zatrzymuje funkcję w tym miejscu. Kolejne next() wznawia pracę dokładnie tam, gdzie się zatrzymała.

Każde next() zwraca obiekt { value, done }. Dopóki generator dochodzi do kolejnych yield, pole done ma wartość false. Gdy funkcja skończy działanie albo trafi na return, dostaniesz done: true. Generator jest obiektem iterowalnym, więc przejdziesz po nim pętlą for...of, rozłożysz spreadem [...gen] albo przekażesz do Array.from().

Generatory liczą wartości leniwie, czyli dopiero wtedy, gdy są potrzebne. Dzięki temu mogą opisywać nawet nieskończone ciągi, np. kolejne identyfikatory, bez zajmowania pamięci. yield* przekazuje dalej wszystkie wartości z innego obiektu iterowalnego, a async function* tworzy generator asynchroniczny, po którym przechodzi się pętlą for await...of.

Składnia

#
Składnia
function* name(params) {
  yield value
  yield* iterable
  return finalValue
}

const generator = name()
generator.next()

Więcej przykładów

#
Generator w pętli for...of i w spreadzie
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(`Poziom ${level}`)
}

console.log([...range(0, 20, 5)])
Konsola
Poziom 1
Poziom 2
Poziom 3
[0, 5, 10, 15, 20]
Nieskończony ciąg identyfikatorów
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)
Konsola
task-1
task-2
task-3

Pętla while (true) nie zawiesza programu, bo generator zatrzymuje się na każdym yield i czeka na kolejne wywołanie next().

Łączenie generatorów przez yield*
JavaScript
function* frontend() {
  yield 'HTML'
  yield 'CSS'
}

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

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

Obsługa przeglądarek

#

Szeroko dostępne

Działa we wszystkich nowoczesnych przeglądarkach, także na telefonach. Możesz używać bez obaw.

  • Chrome
  • Edge
  • Firefox
  • Safari

Dobre praktyki

#
  • Po generatorze można przejść tylko raz. Gdy potrzebujesz wartości ponownie, wywołaj funkcję generatora jeszcze raz albo zapisz wyniki w tablicy.
  • Wartość z return ma done: true, więc pętla for...of i spread ją pomijają. Wszystko, co ma trafić do wyniku, oddawaj przez yield.
  • Nie rozkładaj spreadem ani przez Array.from() generatora nieskończonego. Pobieraj z niego wartości przez next() albo przerwij pętlę instrukcją break.

Powiązane hasła

#

Widzisz błąd albo brakuje przykładu? Napisz do nas.