Pętle w JavaScript

Cześć! To jest fragment książki JavaScript od zupełnych podstaw, która ma pomóc w nauce programowania od zera. Zaangażuj się zostawiając komentarze (najedź myszką na tekst, by zobaczyć po prawej dymek komentowania), albo zostań recenzentem.

Tak jak mówiliśmy w pierwszym rozdziale, każda linia kodu jest instrukcją. kolejno wykonywaną od góry do dołu.

console.log("To zostanie wypisane najpierw");
console.log("a to potem");

// Wypisze:
// To zostanie wypisane najpierw
// a to potem

Kolejność wykonywania instrukcji nazywamy przepływem sterowania. Jest to istotne, ponieważ zdarzają się pewne instrukcje, które zmieniają ten przepływ — dokładniej przeskakują w inne miejsce. Jedną z nich już poznaliśmy — instrukcja if pozwala nam ominąć część kodu, gdy warunek nie jest spełniony. Do tej pory jednak nie byliśmy w stanie sprawić, by pojedyncze polecenie wykonało się więcej niż raz. Tę barierę przełamiemy dopiero teraz, a posłużą nam do tego właśnie pętle.

Pętla while

Definicja pętli while niewiele różni się od warunku if. Tutaj słowo-klucz while wskakuje zamiast if, a ich zachowania są tożsame.

Jeśli warunek nie jest spełniony (zwraca false), to ciało jest pomijane (podobnie jak w przypadku instrukcji warunkowej if).

while (false) {
  console.log("Ten tekst nigdy się nie wypisze");
}
if (false) {
  console.log("Ten tekst nigdy się nie wypisze");
}
// Nic się nie drukuje

Jeśli jednak warunek jest spełniony (zwraca true), to ciało zostanie wywołane. Tutaj while różni się od if tym, że warunek sprawdzamy ponownie, po czym jeśli wciąż jest spełniony, to wywołujemy ciało jeszcze raz. Ten proces powtarzamy tak długo, aż finalnie warunek nie będzie spełniony.

W poniższym przypadku pierwszy warunek będzie spełniony tylko raz, bo w ciele zmieniamy wartość zmiennej toBePrinted na false. Drugi będzie spełniony trzykrotnie, bo w ciele zwiększamy wartość zmiennej, aż w końcu jej wartość będzie większa od 2.

let toBePrinted = true;
while (toBePrinted) {
  console.log("Będzie wypisane tylko raz");
  toBePrinted = false;
}
// Wypisze:
// Będzie wypisane tylko raz

let printedTimes = 0;
while (printedTimes <= 2) {
  console.log("Wypisane dla " + printedTimes);
  printedTimes += 1;
  // czyli inaczej printedTimes = printedTimes + 1
}
// Wypisze:
// Wypisane dla  0
// Wypisane dla  1
// Wypisane dla  2

Wracając do historii Jasia, pętli można użyć, aby oddać polecenie jego mamy "Będziesz pisał wypracowanie, dopóki go nie skończysz".

while (!esseyFinished) {
  writeEssey();
}

Jeśli w pętli umieścilibyśmy warunek, który zawsze jest spełniony, pętla ta będzie wykonywana w nieskończoność. Tak więc poniższy program jest najprostszym sposobem na zablokowanie przeglądarki, ponieważ nieustannie będzie wypisywał do konsoli ten sam tekst.

// Robisz to na własną odpowiedzialność
while (true) {
  console.log("LOL");
}

Oznacza to, że ciało pętli może zostać wykonane od zera aż do nieskończonej liczby powtórzeń. Pętla, która nigdy się nie kończy, nazywana jest pętlą nieskończoną. W niektórych językach programowania jest ona wykorzystywana. W JavaScript częściej jest wynikiem błędu programisty.

Typowa sytuacją użycia pętli ma miejsce, gdy w ciele poszerzamy jej wartość, aż będzie ona większa od ograniczenia górnego. Tak tworzy się znane nam ze szkoły ciągi liczbowe. Jeśli chcielibyśmy wypisać kolejne wielokrotności cyfry 3 (gdzie kolejny element powstaje poprzez dodanie kolejnej 3 do poprzedniej), moglibyśmy użyć następującej pętli:

let i = 3;
while (i <= 10) {
  console.log(i);
  i += 3; // albo i = i + 3;
}

// Wypisze:
// 3
// 6
// 9

Jeśli chcielibyśmy wypisać ciąg kolejnych potęg liczby 2 (gdzie kolejny element powstaje poprzez podwojenie kolejnego), moglibyśmy użyć następującej pętli:

let i = 1;
while (i <= 100) {
  console.log(i);
  i *= 2; // albo i = i * 2;
}

// Wypisze:
// 1
// 2
// 4 
// 8 
// 16
// 32
// 64

Ćwiczenie: Wartości w ciągach

  • Wypisz kolejne liczby parzyste (wielokrotności 2) zaczynając od 0, a mniejsze od 100.
  • Wypisz kolejne wielokrotności 7 zaczynając od 0, a mniejsze od 100.
  • Wyświetl kolejne wartości powstałe w wyniku wielokrotnego potrajania liczby, zaczynając od 13, tak długo, jak długo wynik jest mniejszy niż 1000.
  • Wypisz kwadraty kolejnych całkowitych liczb mniejszych od 1000.

Odpowiedzi na końcu książki.

Operatory inkrementacji ++ i dekrementacji --

Gdy używamy pętli częstą operacją jest dodanie 1 do wartości zmiennej. Można to zrobić poprzez variable = variable + 1 albo variable += 1. Widzieliśmy to już w przedstawionym wcześniej przykładzie dla printedTimes. Z uwagi na częstotliwość tej czynności, programiści stworzyli specjalny operator do dodawania 11. Jest to tzw. operator inkrementacji, który zapisuje się jako ++. Tak więc variable += 1 albo variable = variable + 1 możemy zamienić na variable++.

let printedTimes = 0;
while (printedTimes <= 2) {
   console.log("Wypisane dla " + printedTimes);
   printedTimes++;
}
// Wypisze:
// Wypisane dla  0
// Wypisane dla  1
// Wypisane dla  2

Analogicznie, odjęcie 1 od wartości zmiennej można zrobić poprzez użycie operatora dekrementacji --. Tak więc variable -= 1 albo variable = variable — 1 możemy zamienić na variable--.

let n = 4;
while (n >= 2) {
   console.log("Wypisane dla " + n);
   n--;
}
// Wypisze:
// Wypisane dla  4
// Wypisane dla  3
// Wypisane dla  2

Zarówno operator inkrementacji ++ jak i dekrementacji -- możemy umieścić przed zmienną (++variable, --variable), jak i po zmiennej (variable++, variable--). Różnica między nimi wybiega poza zakres tej książki, ale zainteresowanym polecam poczytać o postinkrementacji i preinkrementacji (oraz postdekrementacji i predekrementacji).

Pętla for

Pętle często wykorzystuje się aby wykonać jakąś operację dla kolejnych liczb. Przy użyciu pętli while kolejne cyfry od 0 do 4 mogą być wyświetlone w następujący sposób:

let i = 0;
while (i <= 4) {
  // Ciało pętli, na przykład:
  console.log(i);
  i++; // To samo co i = i + 1
}

// Wypisze:
// 0
// 1
// 2
// 3
// 4

Aby uprościć ten wzorzec wymyślona została pętla for, która zachowuje się bardzo podobnie, ale dostarcza w jednym miejscu przestrzeń na:

  • zdefiniowanie zmiennej określającej aktualną liczbę (np. let i = 0),
  • określenie, kiedy pętla powinna się zakończyć (np. i <= 4),
  • określenie, jak powinna być modyfikowana wartość tej zmiennej (np. i++).

Wymienione elementy to kolejne części wewnątrz nawiasów w pętli for. Oddzielamy je od siebie średnikami, natomiast cała reszta wygląda tak samo, jak w pętli while.

Poniżej wykorzystujemy pętlę for do wypisania kolejnych liczb od 0 do 4.

for (let i = 0; i <= 4; i++) {
  console.log(i);
}

// Wypisze:
// 0
// 1
// 2
// 3
// 4

Warto zaznaczyć, że pętla for jest niczym innym, jak wygodniejszą formą pętli while, na którą zawsze może być przetłumaczona. Przyjrzyj się poniższemu porównaniu, które pomoże Ci zapamiętać sens kolejnych części w bloku for: Pierwsza część stałaby przed pętlą while, druga w jej warunku, a trzecia na końcu jej ciała.

for (varDefinition; predicate; varUpdate) {
  code
}

// Jest jednoznaczne z

variableDef
while (predicate) {
  code
  varUpdate
}

Różne przypadki użycia

We współczesnym programowaniu rzadko kiedy zobaczysz użycie pętli while w kodzie. Nie znaczy to jednak, że nie jest istotna, chociaż została ukryta przez nowocześniejsze alternatywy. Niemniej, niejednokrotnie przewija się koncept powtarzania jakiejś operacji tak długo, jak długo warunek jest spełniony.

Pętla for jest używana częściej, zazwyczaj do robienia czegoś dla kolejnych liczb lub określoną ilość razy. Mamy kilka typowych przypadków zastosowania pętli for, które warto zapamiętać.

Poznaliśmy już pierwszy: kiedy potrzebujemy wykonać operację dla kolejnych liczb całkowitych, od pierwszej aż do ostatniej. W poprzednim przykładzie zaczęliśmy od 0, a skończyliśmy na 4. Można uogólnić ten wzorzec dla dowolnych wartości, zaczynając od firstValue a kończąc na lastValue.

for (let i = firstValue; i <= lastValue; i++) {
  // code
}

// Przykład

for (let i = 0; i <= 4; i++) {
  console.log(i);
}

// Wypisze:
// 0
// 1
// 2
// 3
// 4

Kolejny wariant tego wzorca ma miejsce w sytuacji, gdy chcemy zrobić coś dla wszystkich liczb, z wyjątiem ostatniej. W takim przypadku powinniśmy użyć < zamiast <=. Zauważ, że na poniższym przykładzie nie została wypisana cyfra 4.

for (let i = firstValue; i < oneAfterLastValue; i++) {
  // code
}

// Przykład

for (let i = 0; i < 4; i++) {
  console.log(i);
}

// Wypisze:
// 0
// 1
// 2
// 3

Inna spotykana modyfikacja zaistnieje wówczas, gdy nie interesują nas kolejne liczby, a na przykład co druga lub co trzecia. W takim przypadku zamiast i++, powinniśmy użyć i += 2 czy i += 3.

for (let i = firstValue; i <= lastValue; i += step) {
  // code
}

// Przykład

for (let i = 0; i <= 10; i += 3) {
  console.log(i);
}

// Wypisze:
// 0
// 3
// 6
// 9

Ostatni istotny wariant to taki, w którym chcemy odwrócić kolejność liczb i zacząć od największej, a kończyć na mniejszych. W takim przypadku powinniśmy zacząć od największej liczby, w warunku użyć najmniejszej, a przy modyfikacji zmniejszać zmienną (na przykład przy użyciu operatora dekrementacji --).

for (let i = firstValue; i >= lastValue; i--) {
  // code
}

// Przykład

for (let i = 4; i >= 0; i--) {
  console.log(i);
}

// Wypisze:
// 4
// 3
// 2
// 1
// 0

Zauważ, że te wszystkie modyfikacje mogą się łączyć na różne sposoby. Dla przykładu, możemy zacząć od 10, zmniejszać o 2 w każdym kroku aż do 2, a na koniec pominąć ostatnią cyfrę.

for (let i = 10; i > 2; i = i - 2) {
  console.log(i);
}

// Wypisze:
// 10
// 8
// 6
// 4

Pętle w JavaScript wspierają także instrukcje break (powoduje natychmiastowe wyjście z pętli) oraz continue (ominięcie reszty ciała). Początkowo, naśladując większość książek opisałem je, ale zdecydowałem się usunąć tę sekcję. Zrobiłem tak, ponieważ sam nie użyłem oraz nie widziałem ich w żadnym produkcyjnym kodzie przynajmniej od roku — a celem tej książki jest skoncentrowanie się na aspekcie praktycznym, a nie samej teorii. Aby mieć pewność, przeszukałem kilka dużych projektów JavaScript w firmie słynącej z dobrego kodu i również nie natknąłem się na ani jeden przykład ich zastosowania.

Ćwiczenie: Przypadki użycia pętli for dla liczb

  • Wypisz liczby od 10 do 5.
  • Wypisz liczby od 5 do 30, z pominięciem ostatniej.
  • Wypisz co drugą liczbę od 20 do 0.

Odpowiedzi na końcu książki.

Zakończenie

Wbrew przekonaniu, że pętle same w sobie nie są współcześnie tak często używane, to jednak uznaję je za bardzo ważny rozdział. Wszechobecne jest robienie czegoś kilkukrotnie lub dla każdego elementu, dlatego poznanie i zrozumienie pętli będzie procentowało.

Tymczasem przejdziemy do funkcjonalności, która zdominowała współczesne projekty programistyczne, a przez wielu ekspertów określana jest jako najistotniejsza funkcjonalność języków programowania. Czas pomówić o funkcjach.

1:

Cóż, ponoć programiści są znani ze swojego lenistwa.