Generatory – niezrozumiałe fragmenty

Projekt specyfikacji ECMAScript 6 przyniósł już wiele przyjemności współczesnym programistom JavaScriptu. W poprzednim wpisie omawialiśmy nowe klasy zbiorów i pętle iteracyjne for..of. W tym poście omówimy coś, co jest nierozerwalnie związane z pętlami for..of: funkcje generatora.

W internecie jest już mnóstwo ciekawych materiałów, które wyjaśniają, dlaczego i jak używać generatorów. Krótko mówiąc, generatory to specjalne funkcje, które tworzą iteracje, a iteracje to obiekty, które mają metodę next(), którą można wywołać, aby uzyskać wartość. W ramach funkcji generatora kluczowe słowo yield określa wartość dla next(). Użycie yield wstrzymuje wykonywanie funkcji generatora, zachowując stan do momentu ponownego wywołania funkcji next(), po czym kod wraca do działania i kontynuuje, aż yield inną wartość (lub do momentu zakończenia działania funkcji generatora). Funkcja generatora ma kilka typowych zastosowań, np. może służyć do iteracji liczb w ciągu Fibonacciego.

Po omówieniu podstaw przyjrzyjmy się bliżej przykładowi kodu JavaScript, który zawiera niektóre z problemów, jakie mogą się pojawić podczas pracy z generatorami. W kodzie znajdują się obszerne komentarze, a przed przeczytaniem kodu możesz pobawić się jego aktywowaną wersją:

Jakie są najważniejsze wnioski z tego kodu?

Po pierwsze, utworzenie generatora powoduje powstanie unikalnego iteratora ze swoim własnym stanem. Możesz też przekazać konstruktorowi generatora parametry, które mogą kontrolować jego działanie.

Po drugie, możesz przekazać parametr podczas wywołania metody next() iteratora. Ta wartość zostanie przypisana do tego, co znajduje się po lewej stronie instrukcji yield z poprzedniego wywołania iteratora. To świetny sposób na zróżnicowanie danych wyjściowych licznika. W tym przypadku używamy go do określenia, czy zwracane słowo ma być zapisane wielkimi literami. Jeśli chcesz wpływać na pierwszą zwracaną wartość, użyj parametru w konstruktorze generatora.

Generatory mogą też generować skończone lub nieskończone iteratory. Jeśli używasz nieskończonego iteratora, pamiętaj, aby ustawić warunek końcowy oparty na wartości yielded. Bardzo łatwo jest przypadkowo napisać nieskończoną pętlę, zwłaszcza gdy używasz instrukcji for..of do iteracji. Jeśli używasz skończonego iteratora za pomocą wywołań funkcji next(), właściwość .done zwracanego obiektu sygnalizuje, czy iteracja została zakończona.

Mamy nadzieję, że ten przykładowy kod wraz z innymi zasobami dostępnymi w internecie wzbudzi Twoje zainteresowanie i zmotywuje do zastanowienia się nad tym, jak możesz używać generatorów w swoim kodzie. Wersje Firefoksa od 31 i Chrome od 39 obsługują generatory natywnie. Projekt Regenerator oferuje obsługę generatora w innych przeglądarkach. Można też użyć narzędzia Traceur.

Dziękujemy Erikowi Arvidssonowi za pomoc w sprawdzaniu tego artykułu.