Przepływ kontrolny to kolejność, w jakiej interpreter JavaScript wykonuje działanie wyciągów. Jeśli skrypt nie zawiera instrukcji zmieniających jego przepływ, jest wykonywane od początku do końca, po jednym wierszu. Struktury kontrolne są służy do określenia, czy zbiór instrukcji został wykonany na podstawie określonego zestawu kryteriów, wielokrotnie wykonywać zestaw instrukcji lub przerywać ciągu instrukcji.
Instrukcje warunkowe
Instrukcje warunkowe określają, czy kod powinien być wykonywany na podstawie
więcej warunków. Instrukcja warunkowa wykonuje zawarty w niej kod, jeśli
powiązany warunek (lub zestaw warunków) zwraca wartość true
. W przeciwnym razie
czy kod został pominięty.
if
…else
Instrukcja if
ocenia warunek w nawiasach pasujących do wyrażenia, które
obserwuj. Jeśli warunek w nawiasie przyjmuje wartość true
, w argumencie
instrukcja lub blokada
za pasującym do niej nawiasem jest wykonywany:
if ( true ) console.log( "True." );
> "True."
if ( true ) {
const myString = "True.";
console.log( myString );
}
> "True."
Jeśli warunek w nawiasie przyjmuje wartość false
, wyrażenie, które
jest ignorowany:
if ( false ) console.log( "True." );
Słowo kluczowe else
bezpośrednio po instrukcji if
i jej
Warunkowo wykonywana instrukcja wskazuje instrukcję do wykonania, jeśli
Warunek if
przyjmuje wartość false
:
if ( false ) console.log( "True." )''
else console.log( "False" );
> "False."
Aby połączyć kilka instrukcji if
, możesz utworzyć
warunkowo wykonana instrukcja po else
innej instrukcji if
:
const myCondition = 2;
if ( myCondition === 5 ) console.log( "Five." );
else if ( myCondition === 2 ) console.log( "Two." );
Zdecydowanie zalecamy użycie składni instrukcji blokowych z uwzględnieniem warunków warunkowych,
poprawia czytelność, ale klauzule else if
są często wyjątkiem od tej reguły:
if ( myCondition === 5 ) {
console.log( "Five." );
} else if ( myCondition === 3 ) {
console.log( "Three" );
} else {
console.log( "Neither five nor three." );
}
> "Neither five nor three."
Operator potrójny
if
warunkowo wykonuje instrukcję. Operator potrójny (dokładniejszy
ale rzadziej nazywany potrójnym operatorem warunkowym).
warunkowego wykonania wyrażenia. Jak sama nazwa wskazuje, potrójny
to jedyny operator JavaScript, który korzysta z trzech operandów:
- Warunek do sprawdzenia, a po nim znak zapytania (
?
). - Wyrażenie, które ma zostać wykonane, jeśli warunek jest zwracany jako
true
, po którym następuje znak dwukropek (:
). - Wyrażenie, które zostanie wykonane, jeśli warunek przyjmuje wartość
false
.
Często używa się go do warunkowania lub przekazywania wartości:
const myFirstResult = true ? "First value." : "Second value.";
const mySecondResult = false ? "First value." : "Second value.";
myFirstResult;
> "First value."
mySecondResult;
> "Second value."
switch
…case
Używaj instrukcji switch
do porównywania wartości wyrażenia z listą
potencjalne wartości zdefiniowane za pomocą co najmniej jednego case
słowa kluczowego. Ta składnia jest
niespotykaną, ponieważ pochodzi ona z najwcześniejszych decyzji związanych z projektowaniem JavaScript.
Składnia switch
...case
zawiera słowo kluczowe switch
, a po nim wyrażenie
ujęte w nawiasy, a po niej dopasowane nawiasy klamrowe.
Treść switch
może zawierać case
słów kluczowych, zwykle jedno lub więcej,
po którym następuje wyrażenie lub wartość oraz dwukropek (:
).
Gdy interpreter osiągnie wartość case
z wartością pasującą do wyrażenia
oceniane w nawiasach po słowie kluczowym switch
, wykonuje ono dowolne
instrukcje po tej klauzuli case
:
switch ( 2 + 2 === 4 ) {
case false:
console.log( "False." );
case true:
console.log( "True." );
}
> "True."
Wszystkie instrukcje po pasujących case
są wykonywane, nawet jeśli są
zawarte w instrukcji block.
switch ( 2 + 2 === 4 ) {
case false:
console.log( "False." );
case true:
let myVariable = "True.";
console.log( myVariable );
}
> "True."
Jedną z pułapek korzystania z funkcji switch…case
jest to, że po znalezieniu dopasowania
Interpreter JavaScript wykonuje dowolną instrukcję, która następuje po dopasowanej instrukcji case
,
nawet te zawarte w innych klauzulach case
. Jest to tzw. „przełamanie”. do
następny case
:
switch ( 2 + 2 === 7 ) {
case false:
console.log( "False." );
case true:
console.log( "True." );
}
> "False."
> "True."
Aby tego uniknąć, zakończ każdy przypadek słowem kluczowym break
, które
natychmiast zatrzymuje ocenę treści switch
:
switch ( 2 + 2 === 7 ) {
case false:
console.log( "False." );
break;
case true:
console.log( "True." );
break;
}
> "False."
Jeśli żaden element case
nie pasuje do wartości warunkowej, funkcja switch
wybiera default
klauzuli, jeśli występuje:
switch ( 20 ) {
case 5:
console.log( "The value was five." );
break;
case 10:
console.log( "The value was ten." );
break;
default:
console.log( "The value was something unexpected." );
}
> "The value was something unexpected."
Reklamy zastępcze mają jednak zastosowanie również do zdarzenia default
, co może prowadzić do
nieoczekiwane rezultaty. Aby rozwiązać ten problem, zakończ wyrażenie default
wyrażeniem break
,
lub umieścić je na ostatnim miejscu na liście zgłoszeń.
switch ( 20 ) {
default:
console.log( "The value was something unexpected." );
case 10:
console.log( "The value was ten." );
break;
case 5:
console.log( "The value was five." );
break;
}
> The value was something unexpected.
> The value was ten.
Ponieważ klauzule case
nie wymagają parametru
Instrukcja block do grupowania
jeśli jest wiele instrukcji, klauzule case
i default
nie tworzą
zakres leksykalny samodzielnie:
let myVariable;
switch ( true ) {
case true:
let myVariable = "True.";
break;
default:
let myVariable = "False.";
break;
}
> Uncaught SyntaxError: redeclaration of let myVariable
Aby zarządzać zakresem, użyj instrukcji blokowania:
let myVariable;
switch ( true ) {
case true: {
let myVariable = "True.";
break;
}
default: {
let myVariable = "False.";
break;
}
}
Pętle i iteracja
pętle umożliwiają powtarzanie zestawu instrukcji tak długo, jak długo spełniony jest warunek; do momentu spełnienia warunku. Wykonuj zapętlone instrukcje zestawu instrukcji do uzyskania określonego wyniku lub do momentu, gdy tłumacz dochodzi do końca iteracyjnej struktury danych (np. ostatniego elementu w argumencie tablica, mapa lub zbiór, końcowa właściwość obiektu lub ostatni znak w argumencie ciąg znaków).
Pętle przecinają ruch „od góry do dołu” przebieg wykonania skryptu przez iterację w zbiorze instrukcji do momentu spełnienia co najmniej jednego z warunków lub w zależności od składni użytej do utworzenia pętli. Po zakończeniu pętli, będzie kontynuowane do następujących po nim instrukcji. W poniższym przykładzie instrukcje w treści pętli są wykonywane 3 razy przed tłumacz przechodzi dalej:
let iterationCount = 0;
console.log( "Pre-loop." );
while( iterationCount < 3 ) {
iterationCount++;
console.log( "Loop iteration." );
}
console.log( "Continuing on." );
> "Pre-loop."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
> "Continuing on."
Jeśli warunki nie zostaną spełnione podczas wykonywania pętli, pętla będzie kontynuowana bez ograniczeń czasowych. Te pętle nieskończone to typowa pułapka programowania, która może powoduje główny wątek wykonania. aby wstrzymać ją na stałe, a nawet zawiesić kartę przeglądarki.
Ten przykład jest wykonywany tak długo, jak pozostaje wartość logiczna true
true
Wartości logiczne są stałe,
spowoduje to nieskończoną pętlę.
console.log( "Pre-loop." );
while( true ) {
console.log( "Loop iteration." );
}
> "Pre-loop."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
…
Unikaj pozostawiania w kodzie produkcyjnym nieskończonych zapętleń. Jeśli przypadkowo utworzysz w trakcie programowania, możesz rozwiązać problem, zamykając kartę przeglądarki, w której działa. zaktualizowanie kodu, tak aby pętla nie była już nieskończona, i ponowne uruchomienie stronę.
while
Pętla while
jest tworzona za pomocą słowa kluczowego while
, po którym następuje parę
w nawiasach znajduje się warunek do sprawdzenia. Jeśli określony
warunek przyjmuje początkowo wartość true
, wyrażenie (lub
instrukcja blokowa), która następuje po
nawiasy są wykonywane. W przeciwnym razie pętla nigdy się nie uruchamia. Po każdym
powtórzenia, warunek jest sprawdzany ponownie, a jeśli ma on nadal wartość true
, pętla
i powtarzania.
let iterationCount = 0;
while( iterationCount < 3 ) {
iterationCount++;
console.log( `Loop ${ iterationCount }.` );
}
> "Loop 1."
> "Loop 2."
Jeśli tłumacz znajdzie instrukcję continue
w pętli while
, zatrzymuje ją
powtórzenia, ponownie ocenia warunek i, jeśli to możliwe, kontynuuje pętlę:
let iterationCount = 0;
while( iterationCount <= 5 ) {
iterationCount++;
if( iterationCount === 3 ) {
continue;
}
console.log( `Loop ${ iterationCount }.` );
}
console.log( "Loop ended." );
> "Loop 1."
> "Loop 2."
> "Loop 4."
> "Loop 5."
> "Loop ended."
Jeśli tłumacz znajdzie instrukcję break
w pętli while
, oznacza to, że iteracja
zatrzymuje się, a warunek nie jest sprawdzany ponownie, dzięki czemu tłumacz może przejść dalej:
let iterationCount = 1;
while( iterationCount <= 5 ) {
if( iterationCount === 3 ) {
console.log(`Iteration skipped.``);`
break;
}
console.log( `Loop ${ iterationCount }.` );
iterationCount++;
}
console.log( "Loop ended." );
> "Loop 1."
> "Loop 2."
> "Iteration skipped.
> "Loop ended."
Za pomocą while
możesz wykonać określoną liczbę powtórzeń, tak jak widać w
w poprzednim przykładzie, ale najczęstszym przypadkiem użycia funkcji while
jest pętla
nieokreślona długość:
let randomize = () => Math.floor( Math.random() * 10 );
let randomNum = randomize();
while( randomNum !== 3 ){
console.log( `The number is not ${ randomNum }.` );
randomNum = randomize();
}
console.log( `The correct number, ${ randomNum }, was found.` );
> "The number is not 0."
> "The number is not 6."
> "The number is not 1."
> "The number is not 8."
> "The correct number, 3, was found."
do
…while
do
...while
to wariant pętli while
, w której funkcja warunkowa
ocena ma miejsce na końcu każdej iteracji pętli. Oznacza to, że
treść pętli jest zawsze wykonywana co najmniej raz.
Aby utworzyć pętlę do
...while
, użyj słowa kluczowego do
, a po nim instrukcji
(lub instrukcji blokowania),
wykonywane przy każdej iteracji pętli. Bezpośrednio po tym wyrażeniu dodaj
while
i dopasowane nawiasy zawierające warunek do sprawdzenia. Kiedy
ten warunek nie jest już zwracany jako true
, pętla się kończy.
let iterationCount = 1;
do {
console.log( `Loop ${ iterationCount }.` );
iterationCount++;
} while ( iterationCount < 3 );
> "Loop 1."
> "Loop 2."
> "Loop 3."
Podobnie jak w przypadku pętli while
, najczęstszym przypadkiem użycia funkcji do
...while
jest pętla
nieokreślona długość:
let randomNum;
do {
randomNum = ( () => Math.floor( Math.random() * 10 ) )();
console.log( `Is the number ${ randomNum }?` );
} while ( randomNum !== 3 );
console.log( `Yes, ${ randomNum } was the correct number.` );
> "Is the number 9?"
> "Is the number 2?"
> "Is the number 8?"
> "Is the number 2?"
> "Is the number 3?"
> "Yes, 3 was the correct number."
for
Użyj pętli for
, aby iterować ponad znaną ilość. W starszych bazach kodu było to
często używane do iteracji elementów w tablicy.
Aby utworzyć pętlę for
, użyj słowa kluczowego for
, a następnie zestawu nawiasów
które akceptuje 3 poniższe wyrażenia w kolejności i oddzielone znakiem
średniki:
- Wyrażenie do sprawdzenia po rozpoczęciu pętli
- Warunek określający, czy pętla ma być kontynuowana
- wyrażenie do wykonania na końcu każdej pętli.
Po nawiasach dodaj wyrażenie (zwykle instrukcja blokowa), która ma być wykonywane w trakcie pętli.
for( let i = 0; i < 3; i++ ) {
console.log( "This loop will run three times.")
}
Pierwsze wyrażenie inicjuje zmienną, która działa jak licznik. Ten
jest oceniane raz przed pierwszą iteracją pętli. Dostępne opcje
zainicjuj tę zmienną za pomocą algorytmu let
(lub wcześniej var
) jak dowolnego innego
zmienną, a jej zakresem jest treść pętli. Te zmienne mogą mieć dowolne
prawidłowy, ale często nazywa się go i
ze względu na „iteracja” czy „indeks”.
Wydaje się to sprzeczne z przyjętym
sprawdzone metody tworzenia przewidywalnych nazw identyfikatorów,
ale konwencja jest na tyle dobrze ugruntowana, aby inni programiści mogli
wystarczy spojrzeć. Ponieważ zindeksowane kolekcje nie są indeksowane,
te zmienne niemal zawsze mają początkową wartość 0
.
Podobnie jak w przypadku innych form pętli, warunek jest wyrażeniem określającym,
czy pętla ma zostać wykonana. Najczęściej używa się go do ustawienia górna część
dla licznika iteracji. Tłumacz ocenia warunek przed
wykonując pętlę for
po raz pierwszy.Jeśli warunek nie zostanie
do true
, treść pętli nie jest wykonywana.
Ostatnie wyrażenie jest wykonywane na końcu każdej iteracji w pętli. Zwykle służy do zwiększania identyfikatora o 1.
Najczęściej występujące pętle for
powtarzają się przez tablice w starszych wersjach
w postaci baz kodu. W tych przypadkach warunek kontynuacji pętli jest
liczba iteracji mniejsza od lub równa długości iterowanej tablicy
przez telefon. Zmienna używana do śledzenia bieżącej liczby iteracji jest używana do wyszukiwania
wartość powiązaną z tym indeksem w tablicy, umożliwiając każdemu elementowi
tablicę, na której należy podjąć działanie w kolejności:
var myArray = [ true, false, true ];
for( let i = 0; i <= myArray.length; i++ ) {
console.log( myArray[ i ] );
}
> true
> false
> true
Takie podejście przestało być wykorzystywane i zaczęło obowiązywać bardziej nowoczesne podejście do zapętlanie się iteracjonalnych struktur danych.
for
[...] of
[...]
Pętle for
...of
... umożliwiają iterację wartości zapisanych w
elastyczną strukturę danych, np. tablica, zbiór czy mapa.
Pętla for
...of
... używa słowa kluczowego for
, po którym następuje zestaw nawiasów
zawiera zmienną, a po niej ciąg of
i powtarzaną strukturę danych
ponad. Zmienną może być deklaracją wykonaną tutaj za pomocą funkcji let
, const
lub
var
, zmienna zadeklarowana wcześniej w bieżącym zakresie, obiekt
usługi lub przypadkiem wystąpienia
niszczenie przypisania.
Zawiera wartość elementu, który odpowiada bieżącej iteracji
w pętli.
const myIterable = [ true, false, true ];
for( const myElement of myIterable ) {
console.log( myElement );
}
> true
> false
> true
W tym przykładzie użycie parametru const
w parametrze myElement
działa, mimo że myElement
to
otrzymuje nową wartość w każdej iteracji pętli. To dlatego, że zmienne
zadeklarowane za pomocą funkcji let
lub const
mają zakres ograniczony do instrukcji block w
w pętli. Zmienna jest inicjowana na początku każdej iteracji i usuwana na
na końcu tej iteracji.
for
...in
...
Używaj pętli for
...in
... do iteracji według wyliczanych właściwości obiektu,
również wszystkie odziedziczone właściwości. Podobnie jak w przypadku pętli for
...of
...,
for
...in
... pętla używa słowa kluczowego for
, po którym następuje zestaw nawiasów
zawierającej zmienną zawierającą wartość klucza właściwości odpowiadającego
z bieżącą iteracją pętli. Po tej zmiennej następuje określenie
in
, a następnie powtarzany obiekt:
const myObject = { "myProperty" : true, "mySecondProperty" : false };
for( const myKey in myObject ) {
console.log( myKey );
}
> "myProperty"
> "mySecondProperty"
I znów, mimo że wartość myKey
zmienia się z każdym wystąpieniem pętli,
możesz użyć zmiennej const
bez błędów, ponieważ zmienna jest w praktyce odrzucana
na końcu każdej iteracji, a potem odtworzyć na początku.
Wartość powiązana z każdym kluczem usługi nie jest bezpośrednio dostępna dla
for
...in
... składnia. Ponieważ jednak pętla ma dostęp do klucza właściwości w
przy każdej iteracji możesz użyć tego klawisza jego wartość:
const myObject = { "myProperty" : true, "mySecondProperty" : false };
for( const myKey in myObject ) {
const myValue = myObject[ myKey ];
console.log( `${ myKey } : ${ myValue }` );
}
> "myProperty : true"
> "mySecondProperty : false"
Właściwości odziedziczone z wbudowanych konstruktorów są niewyliczalne, co oznacza, że
for
...in
... nie wykonuje iteracji za pomocą właściwości dziedziczonych z Object
za pomocą konstruktora. Jednak wszystkie wymienne właściwości w argumencie
łańcuch prototypów:
const myPrototype = { "protoProperty" : true };
const myObject = Object.create( myPrototype, {
myProperty: {
value: true,
enumerable: true
}
});
for ( const myKey in myObject ) {
const myValue = myObject[ myKey ];
console.log( `${ myKey } : ${ myValue }` );
}
> "myProperty : true"
> "protoProperty : true"
JavaScript udostępnia wbudowane metody określania, czy usługa jest
bezpośrednią właściwość obiektu, a nie właściwości prototypu obiektu;
łańcuch: nowoczesny
Object.hasOwn()
i starszych metod Object.prototype.hasOwnProperty()
. Te
metody sprawdzają, czy określona właściwość jest dziedziczona (czy niezadeklarowana),
zwracanie funkcji true
tylko w przypadku natychmiastowych właściwości określonego obiektu:
const myPrototype = { "protoProperty" : true };
const myObject = Object.create( myPrototype, {
myProperty: {
value: true,
enumerable: true
}
});
for ( const myKey in myObject ) {
const myValue = myObject[ myKey ];
if ( Object.hasOwn( myObject, myKey ) ) {
console.log( `${ myKey } : ${ myValue }` );
}
}
> "myProperty : true"
Istnieją również trzy metody statyczne, które zwracają tablicę składającą się z
klucze wyliczalne (Object.keys()
), wartości (Object.values()
) lub
pary klucz-wartość (Object.entries()
):
const myObject = { "myProperty" : true, "mySecondProperty" : false };
Object.keys( myObject );
> Array [ "myProperty", "mySecondProperty" ]
Umożliwia to powtarzanie kluczy, wartości lub par klucz-wartość obiektu (za pomocą niszczenia przypisania) bez uwzględniania właściwości należących do prototypu tego obiektu:
const myPrototype = { "protoProperty" : "Non-enumerable property value." };
const myObject = Object.create( myPrototype, {
myProperty: {
value: "Enumerable property value.",
enumerable: true
}
});
for ( const propKey of Object.keys( myObject ) ) {
console.log( propKey );
}
> "myProperty"
for ( const propValue of Object.values( myObject ) ) {
console.log( propValue );
}
> "Enumerable property value."
for ( const [ propKey, propValue ] of Object.entries( myObject ) ) {
console.log( `${ propKey } : ${ propValue }` );
}
> "myProperty : Enumerable property value."
forEach()
metody forEach()
udostępniane przez tablica,
Mapa, Plan,
a konstruktory NodeList to przydatny skrót do iteracji danych
w kontekście funkcji wywołania zwrotnego. W przeciwieństwie do innych form pętli
pętla utworzona za pomocą dowolnej metody forEach()
nie może zostać przerwana za pomocą metody break
lub
continue
forEach
to metoda należąca do prototypu każdej struktury danych. Co forEach
oczekuje funkcji wywołania zwrotnego jako argumentu, chociaż różni się ona nieco
w argumentach uwzględnionych przy wywołaniu tej funkcji. Druga, opcjonalna
określa wartość this
, która ma być używana jako kontekst wywołania dla funkcji
funkcji wywołania zwrotnego.
Funkcja wywołania zwrotnego używana z Array.forEach
udostępnia parametry zawierające
wartość bieżącego elementu, indeks bieżącego elementu oraz tablicę, dla której została wywołana metoda forEach
:
const myArray = [ true, false ];
myArray.forEach( ( myElement, i, originalArray ) => {
console.log( i, myElement, originalArray );
});
> 0 true Array(3) [ true, false ]
> 1 false Array(3) [ true, false ]
Funkcja wywołania zwrotnego używana z Map.forEach
udostępnia parametry zawierające
wartość powiązaną z bieżącym elementem, klucz powiązany z bieżącym elementem
, a metoda Mapa forEach
została wywołana w dniu:
const myMap = new Map([
['myKey', true],
['mySecondKey', false ],
]);
myMap.forEach( ( myValue, myKey, originalMap ) => {
console.log( myValue, myKey, originalMap );
});
> true "myKey" Map { myKey → true, mySecondKey → false }
> false "mySecondKey" Map { myKey → true, mySecondKey → false }
Wywołanie zwrotne Set.forEach
zawiera podobne parametry. Ponieważ zestaw nie zawiera
indeksów lub kluczy różniących się od wartości, drugi argument zamiast tego zapewnia
zbędnej, nieistotnej wartości, ściśle aby zachować spójność składni
innych metod forEach
.
const mySet = new Set([ true, false ]);
mySet.forEach( ( myValue, myKey, originalSet ) => {
console.log( myValue, myKey, originalSet );
});
> true true Set [ true, false ]
> false false Set [ true, false ]
Iteratory
Eterowalność to dowolna struktura danych składająca się z pojedynczych elementów, które można
i dokonania kolejnych iteracji przy użyciu metod
opisanych wcześniej. iterator to element
możliwy do powtórzenia obiekt zgodny z protokołem iteratora, co oznacza, że musi implementować
metody next()
, która przechodzi kolejne elementy w elementach, które zawiera,
przy każdym wywołaniu tej metody zwracany jest obiekt dla każdej sekwencji
w określonym formacie.
wbudowane iteracyjne struktury danych JavaScript (takie jak
tablica,
Mapa oraz
Set) nie są iteratorami w
same, ale wszystkie dziedziczą metodę iterator
, dostępną za pomocą
@@iterator
znany symbol,
, który zwraca obiekt iteratora utworzony na podstawie struktury danych iteracyjnej:
const myIterable = [ 1, 2, 3 ];
const myIterator = myIterable[ Symbol.iterator ]();
myIterable;
> (3) [1, 2, 3]
myIterator;
> Array Iterator {}
Wywołanie metody next()
w iteratorze powoduje przejście przez zawarte w niej elementy
zawiera po jednym naraz, przy czym każde wywołanie zwraca obiekt zawierający dwa
właściwości: value
, który zawiera wartość bieżącego elementu, oraz
done
, jest to wartość logiczna wskazująca, czy iterator przekazał ostatni element w argumencie
do struktury danych. Wartość done
wynosi true
tylko w przypadku wywołania next()
powoduje próbę uzyskania dostępu do elementu poza ostatnim elementem
lub iteratorem.
const myIterable = [ 1, 2, 3 ];
const myIterator = myIterable[ Symbol.iterator ]();
myIterator.next();
> Object { value: 1, done: false }
myIterator.next();
> Object { value: 2, done: false }
myIterator.next();
> Object { value: 3, done: false }
myIterator.next();
> Object { value: undefined, done: true }
Funkcje generatora
Zadeklaruj generator, używając słowa kluczowego function*
(zwróć uwagę na gwiazdkę)
lub zdefiniuj wyrażenie funkcji generatora:
function* myGeneratorFunction() { };
Podobnie jak iteratorzy funkcje generatorów zachowują stan. Wywołuję generator zwraca nowy obiekt generatora, ale nie od razu uruchom kod w treści funkcji:
function* myGeneratorFunction() {
console.log( "Generator function body ")
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject;
> Generator { }
typeof myGeneratorObject;
> "object"
Obiekty generatorów są zgodne z protokołem iteratora. Wartość każdego wywołania
Wartość next()
w przypadku zwracanej funkcji generatora jest określona przez wyrażenie yield
,
wstrzymujące wykonanie funkcji generatora i zwracające wartość funkcji generatora,
zawierające słowo kluczowe yield
. Późniejsze połączenia z numerem next()
kontynuuj wykonywanie funkcji, wstrzymując się przy następnym wyrażeniu yield
, a następnie
zwracającą powiązaną wartość.
function* myGeneratorFunction() {
yield "My first yielded value.";
yield "My second yielded value.";
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> Object { value: "My first yielded value.", done: false }
myGeneratorObject.next();
> Object { value: "My second yielded value.", done: false }
Jeśli funkcja next()
zostanie wywołana po nieokreśleniu kolejnych wartości za pomocą yield
,
return
lub throw
(w przypadku błędu) pozostałą część funkcji
treść jest wykonywana, a zwrócony obiekt ma value
o wartości undefined
i done
właściwość true
:
function* myGeneratorFunction() {
console.log( "Start of the generator function." );
yield "First";
console.log( "Second part of the generator function." );
yield "Second";
console.log( "Third part of the generator function." );
yield "Third";
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> "Start of the generator function."
> Object { value: "First", done: false }
myGeneratorObject.next();
> "Second part of the generator function."
> Object { value: "Second", done: false }
myGeneratorObject.next();
> "Third part of the generator function."
> Object { value: "Third", done: false }
myGeneratorObject.next();
> Object { value: undefined, done: true }
Używaj next()
tylko w przypadku obiektu zwracanego przez funkcję generatora, a nie
generatora. W przeciwnym razie każde wywołanie funkcji generatora
tworzy nowy obiekt generatora:
function* myGeneratorFunction() {
yield "First";
yield "Second";
};
myGeneratorFunction().next();
> Object { value: "First", done: false }
myGeneratorFunction().next();
> Object { value: "First", done: false }
Tak jak w przypadku każdej funkcji, funkcja generatora zatrzymuje się po napotkaniu funkcji return
.
słowa kluczowego. Następnie zwraca obiekt do kontekstu wywołania zawierającego
zwróciło wartość i właściwość done
o wartości true
.
function* myGeneratorFunction() {
yield 1;
yield 2;
return 3;
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next().done;
> Object { value: 1, done: false }
myGeneratorObject.next().done;
> Object { value: 2, done: false }
myGeneratorObject.next();
> Object { value: 3, done: true }
Wyrażenie yield
może przyjmować część semantyki identyfikatora,
dwukierunkowa „komunikacja” z i z powrotem do zawieszonej części
generatora. Kiedy wartość jest przekazywana do metody next()
generatora jako
zamiast argumentu, zastępuje wartość powiązaną z poprzednim, zawieszonym
Wyrażenie yield
:
function* myGeneratorFunction() {
const firstYield = yield;
yield firstYield + 10;
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> Object { value: undefined, done: false }
myGeneratorObject.next( 5 );
> Object { value: 15, done: false }
Pamiętaj, że spowoduje to zastąpienie całego wyrażenia powiązanego z
poprzedni yield
i nie tylko ponownie przypisuje wartość poprzedniego elementu yield
do
wartość określona we właściwości next()
:
function* myGeneratorFunction() {
const firstYield = yield;
const secondYield = yield firstYield + 100;
yield secondYield + 10;
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> Object { value: undefined, done: false }
myGeneratorObject.next( 10 ); // Can be thought of as changing the value of the `firstYield` variable to `10
> Object { value: 110, done: false }
myGeneratorObject.next( 20 ); // Can be thought of as changing the value of the `secondYield` variable to `20`, _not_ `20 + 100;`
> Object { value: 30, done: false }
Każdy argument przekazany do pierwszego wywołania funkcji next()
jest ignorowany, ponieważ nie ma
poprzedniego wyrażenia yield
, aby zaakceptować tę wartość. Tak jak w przypadku każdej innej funkcji,
dostępne są argumenty przekazywane do początkowego wywołania funkcji generatora
zakres treści funkcji generatora:
function* myGeneratorFunction( startingValue ) {
let newValue = yield startingValue + 1;
newValue = yield newValue + 10;
yield startingValue + 20;
};
const myGeneratorObject = myGeneratorFunction( 2 );
myGeneratorObject.next( 1 );
> Object { value: 3, done: false }
myGeneratorObject.next( 5 );
> Object { value: 15, done: false }
myGeneratorObject.next( 10 );
Object { value: 22, done: false }
Operator yield*
(zwróć uwagę na gwiazdkę) jest używany z iteracjami, w tym:
innej funkcji generatora do iteracji i uzyskania każdej wartości argumentu
zwraca:
function* mySecondaryGenerator() {
yield 2;
yield 3;
}
function* myGenerator() {
yield 1;
yield* mySecondaryGenerator();
yield 4;
return 5;
}
const myIterator = myGenerator();
myIterator.next();
> Object { value: 1, done: false }
myIterator.next();
> Object { value: 2, done: false }
myIterator.next();
> Object { value: 3, done: false }
myIterator.next();
> Object { value: 4, done: false }
myIterator.next();
> Object { value: 5, done: true }
Asynchroniczny JavaScript
Mimo że JavaScript jest zasadniczo synchroniczny to istnieją mechanizmy, które pozwalają programistom wykorzystać pętlę zdarzeń, która ma zostać wykonana asynchronicznych zadań.
Obietnice
Obietnica to obiekt zastępczy dla wartości, która nie jest znana, gdy obietnica jest Utworzono. To kontener, który dyktuje operację asynchroniczną, działania, które zostaną uznane za sukces lub niepowodzenie, w obu przypadkach i uzyskaną wartość.
Tworzenie instancji Promise za pomocą operatora new
z wbudowanym Promise
za pomocą funkcji konstruktora. Ten konstruktor akceptuje funkcję o nazwie wykonawca
jako argumentu. Ta funkcja wykonawcy jest zwykle wykorzystywana do wykonywania
asynchronicznych działań, a następnie dyktując warunki, według których powinna zostać złożona obietnica
uznanych za zrealizowane lub odrzucone. Obietnica jest określona jako oczekująca.
gdy jest uruchomiona funkcja wykonawcy. Po zakończeniu realizacji przez wykonawcy obietnica
jest uznawany za zrealizowany (lub rozwiązany w niektórych źródłach dokumentacji), jeśli
funkcja wykonawcy i wykonywane przez nią działanie asynchroniczne zostały zakończone
i odrzucona, jeśli funkcja wykonawcy napotka błąd;
wykonywane działanie asynchroniczne kończy się niepowodzeniem. Po spełnieniu obietnicy lub
odrzucono, jest uznawane za rozstrzygnięte.
const myPromise = new Promise( () => { });
Konstruktor wywołuje funkcję wykonawcy za pomocą dwóch argumentów. Te argumenty to funkcje, które pozwalają ręcznie zrealizować lub odrzucić obietnicę:
const myPromise = new Promise( ( fulfill, reject ) => { });
Funkcje służące do realizacji lub odrzucenia obietnicy są wywoływane z wynikiem wartość obietnicy jako argument (zwykle jest to błąd odrzucenia):
const myPromise = new Promise( ( fulfill, reject ) => {
const myResult = true;
setTimeout(() => {
if( myResult === true ) {
fulfill( "This Promise was successful." );
} else {
reject( new Error( "This Promise has been rejected." ) );
}
}, 10000);
});
myPromise;
> Promise { <state>: "pending" }
myPromise;
> Promise { <state>: "fulfilled", <value>: "This Promise was successful." }
Łańcuch obietnic
Na powstałym obiekcie Promise można wykonać działania za pomocą interfejsów then()
, catch()
i
Metody finally()
odziedziczone z konstruktora Promise. Każda z tych opcji
zwraca obietnicę, dla której można natychmiast wykonać działanie za pomocą funkcji then()
,
catch()
lub finally()
, co pozwoli Ci połączyć wynikowe obietnice.
Funkcja then()
udostępnia 2 funkcje wywołania zwrotnego jako argumenty. Wykorzystaj pierwsze z nich do realizacji
wynikową obietnicę, a drugi ją odrzucić. Obie metody
, który nadaje wynikowi Promise wartość.
const myPromise = new Promise( ( fulfill, reject ) => {
const myResult = true;
setTimeout(() => {
if( myResult === true ) {
fulfill( "This Promise was fulfilled." );
} else {
reject( new Error( "This Promise has been rejected." ) );
}
}, 100);
});
myPromise.then( successfulResult => console.log( successfulResult ), failedResult => console.error( failedResult ) );
> "This Promise was successful."
Za pomocą polecenia then()
możesz też obsługiwać tylko stan realizacji, a catch
–
do obsługi stanu odrzucenia. Wywołaj funkcję catch
za pomocą jednego argumentu zawierającego
wartość podana w metodzie odrzucenia obietnicy:
const myPromise = new Promise( ( fulfill, reject ) => {
const myResult = false;
setTimeout(() => {
if( myResult === true ) {
fulfill( "This Promise was fulfilled." );
} else {
reject( new Error( "This Promise has been rejected." ) );
}
}, 100);
});
myPromise
.then( fulfilledResult => console.log(fulfilledResult ) )
.catch( rejectedResult => console.log( rejectedResult ) )
.finally( () => console.log( "The Promise has settled." ) );
> "Error: This Promise has been rejected."
> "The Promise has settled."
W przeciwieństwie do funkcji then
i catch
, które umożliwiają uruchamianie funkcji obsługi, gdy obietnica
zostanie wypełnione lub odrzucone, funkcja przekazana jako argument do funkcji finally
jest wywoływana niezależnie od tego, czy obietnica została spełniona czy odrzucona.
Funkcja obsługi jest wywoływana bez argumentów, ponieważ nie jest przeznaczona
pracować z wartościami przekazanymi z obietnicy, tylko do wykonywania kodu po parametrze
Obietnica skończona.
Równoczesność
Konstruktor Promise udostępnia 4 metody pracy z wieloma powiązanymi
Obietnice – użycie parametru iterable zawierającego obiekty Promise. Te
każda z tych metod zwraca obietnicę, która jest realizowana lub odrzucana na podstawie stanu
z przekazanych mu obietnic. Na przykład Promise.all()
tworzy obietnicę
którą zostanie spełniony tylko wtedy, gdy zostanie spełniony każda obietnica przekazywana do tej metody:
const firstPromise = new Promise( ( fulfill, reject ) => fulfill( "Successful. ") );
const secondPromise = new Promise( ( fulfill, reject ) => fulfill( "Successful. ") );
const thirdPromise = new Promise( ( fulfill, reject ) => fulfill( "Successful. ") );
const failedPromise = new Promise( ( fulfill, reject ) => reject( "Failed.") );
const successfulPromises = [ firstPromise, secondPromise, thirdPromise ];
const oneFailedPromise = [ failedPromise, ...successfulPromises ];
Promise.all( successfulPromises )
.then( ( allValues ) => {
console.log( allValues );
})
.catch( ( failValue ) => {
console.error( failValue );
});
> Array(3) [ "Successful. ", "Successful. ", "Successful. " ]
Promise.all( oneFailedPromise )
.then( ( allValues ) => {
console.log( allValues );
})
.catch( ( failValue ) => {
console.error( failValue );
});
> "Failed."
Metody Promise równoczesności są następujące:
Promise.all()
- Zrealizowany tylko wtedy, gdy wszystkie podane obietnice zostaną spełnione.
Promise.any()
- Wypełniona, jeśli którakolwiek z podanych obietnic zostanie spełniony, a odrzucona tylko jeśli wszystkie obietnice zostaną odrzucone.
Promise.allSettled()
- Zrealizowane, gdy obietnice ustabilizują się, niezależnie od ich wyniku.
Promise.race()
- Odrzucona lub zrealizowana na podstawie wyniku pierwszej obietnicy do rozliczenia, ignorując wszystkie obietnice zawarte w późniejszym czasie.
async
/await
Jeśli używasz słowa kluczowego async
przed deklaracją funkcji
lub wyrażenie funkcji, dowolny
zwracana przez funkcję wartość jest jako spełniona obietnica zawierająca
. Dzięki temu możesz uruchamiać operacje asynchroniczne i zarządzać nimi przy użyciu
w procesie programowania synchronicznego.
async function myFunction() {
return "This is my returned value.";
}
myFunction().then( myReturnedValue => console.log( myReturnedValue ) );
> "This is my returned value."
Wyrażenie await
wstrzymuje wykonywanie funkcji asynchronicznej, podczas gdy
wiążąca obietnica jest wiążąca. Po uzgodnieniu obietnicy wartość
wyrażenie await
to zrealizowana lub odrzucona wartość obietnicy.
async function myFunction() {
const myPromise = new Promise( ( fulfill, reject ) => { setTimeout( () => fulfill( "Successful. "), 5000 ); });
const myPromisedResult = await myPromise;
return myPromisedResult;
}
myFunction()
.then( myResult => console.log( myResult ) )
.catch( myFailedResult => console.error( myFailedResult ) );
> "Successful."
Każda wartość inna niż obietnica zawarta w wyrażeniu await
jest zwracana jako
spełniona obietnica:
async function myFunction() {
const myPromisedResult = await "String value.";
return myPromisedResult;
}
myFunction()
.then( myResult => console.log( myResult ) )
.catch( myFailedResult => console.error( myFailedResult ) );
> "String value."
Sprawdź swoją wiedzę
Jakiego rodzaju pętli używasz, aby iterować według znanej ilości?
for
while
do...while