Utilizziamo i cookie per migliorare la tua esperienza sul sito
CodeWorlds

Pętle i iteracje

W Parku Jurajskim rutynowe zadania muszą być wykonywane regularnie i powtarzalnie: sprawdzanie ogrodzenia każdego wybiegu co godzinę, monitorowanie wszystkich kamer bezpieczeństwa, aktualizacja statusu zdrowia każdego dinozaura. Ręczne wykonywanie tych czynności byłoby żmudne i podatne na błędy.

Podobnie w JavaScript, pętle pozwalają na automatyczne i efektywne wykonywanie powtarzalnych operacji. Zamiast pisać ten sam kod wielokrotnie, możemy użyć pętli do wykonania go dla wielu elementów lub określoną liczbę razy.

Pętla for

Pętla

for
jest jedną z najpopularniejszych pętli w JavaScript. Składa się z trzech części: inicjalizacji, warunku i wyrażenia aktualizującego.

1// Podstawowa struktura pętli for
2for (inicjalizacja; warunek; aktualizacja) {
3  // Blok kodu do wykonania
4}

W praktyce w Parku Jurajskim, możemy użyć pętli

for
do automatyzacji rutynowych zadań:

1// Sprawdzanie stanu zdrowia każdego dinozaura w sektorze
2let dinozaury = ["Tyranozaur", "Velociraptor", "Triceratops", "Stegozaur", "Brachiozaur"];
3
4for (let i = 0; i < dinozaury.length; i++) {
5  console.log(`Sprawdzanie stanu zdrowia: ${dinozaury[i]}`);
6  // Kod sprawdzający stan zdrowia konkretnego dinozaura...
7}
8
9// Wynik:
10// Sprawdzanie stanu zdrowia: Tyranozaur
11// Sprawdzanie stanu zdrowia: Velociraptor
12// Sprawdzanie stanu zdrowia: Triceratops
13// Sprawdzanie stanu zdrowia: Stegozaur
14// Sprawdzanie stanu zdrowia: Brachiozaur
15
16// Monitoring kamer bezpieczeństwa
17for (let kamera = 1; kamera <= 10; kamera++) {
18  console.log(`Sprawdzanie kamery #${kamera}`);
19  // Kod analizujący obraz z kamery...
20}
21
22// Generowanie raportu dziennego za ostatnie 7 dni
23for (let dzień = 1; dzień <= 7; dzień++) {
24  console.log(`Generowanie raportu za dzień #${dzień}`);
25  // Kod generujący raport za konkretny dzień...
26}

Pętla

for
ma trzy główne elementy:

  1. Inicjalizacja (np.
    let i = 0
    ) - wykonywana raz, przed rozpoczęciem pętli
  2. Warunek (np.
    i < dinozaury.length
    ) - sprawdzany przed każdą iteracją; pętla kończy się, gdy warunek zwraca
    false
  3. Aktualizacja (np.
    i++
    ) - wykonywana po każdej iteracji

Pętla for...of

Pętla

for...of
to nowsza i bardziej elegancka forma pętli, która pozwala na iterację po elementach kolekcji (tablice, stringi, mapy, sety, itp.) bez potrzeby śledzenia indeksów.

1// Struktura pętli for...of
2for (let element of kolekcja) {
3  // Blok kodu do wykonania dla każdego elementu
4}

Pętla

for...of
jest szczególnie przydatna, gdy interesują nas same elementy, a nie ich indeksy:

1// Sprawdzanie stanu zdrowia każdego dinozaura przy użyciu for...of
2let dinozaury = ["Tyranozaur", "Velociraptor", "Triceratops", "Stegozaur", "Brachiozaur"];
3
4for (let dinozaur of dinozaury) {
5  console.log(`Sprawdzanie stanu zdrowia: ${dinozaur}`);
6  // Kod sprawdzający stan zdrowia konkretnego dinozaura...
7}
8
9// Sprawdzanie poziomu zapasów różnych rodzajów pokarmu
10let zapasyPokarmu = {
11  mięso: 500, // kg
12  liście: 1200, // kg
13  owoce: 300, // kg
14  ryby: 200 // kg
15};
16
17// Uwaga: for...of nie działa bezpośrednio na obiektach, ale możemy użyć Object.entries()
18for (let [rodzajPokarmu, ilość] of Object.entries(zapasyPokarmu)) {
19  console.log(`Pokarm: ${rodzajPokarmu}, Ilość: ${ilość} kg`);
20  
21  if (ilość < 300) {
22    console.log(`UWAGA: Niski poziom zapasów ${rodzajPokarmu}! Należy uzupełnić.`);
23  }
24}
25
26// Wynik:
27// Pokarm: mięso, Ilość: 500 kg
28// Pokarm: liście, Ilość: 1200 kg
29// Pokarm: owoce, Ilość: 300 kg
30// Pokarm: ryby, Ilość: 200 kg
31// UWAGA: Niski poziom zapasów ryby! Należy uzupełnić.

Pętla for...in

Pętla

for...in
jest przeznaczona do iteracji po właściwościach obiektu. Zwraca nazwy kluczy (właściwości) obiektu.

1// Struktura pętli for...in
2for (let klucz in obiekt) {
3  // Blok kodu do wykonania dla każdego klucza
4}

Przykład użycia w Parku Jurajskim:

1// Analiza danych o dinozaurze
2let tyranozaur = {
3  gatunek: "Tyrannosaurus Rex",
4  wiek: 12,
5  waga: 8000, // kg
6  długość: 12, // m
7  wysokość: 5.6, // m
8  prędkość: 27, // km/h
9  poziomAgresji: "Bardzo wysoki"
10};
11
12// Wypisanie wszystkich informacji o dinozaurze
13for (let cecha in tyranozaur) {
14  console.log(`${cecha}: ${tyranozaur[cecha]}`);
15}
16
17// Sprawdzenie, które cechy dinozaura przekraczają wartości bezpieczeństwa
18let limityBezpieczeństwa = {
19  waga: 5000, // kg
20  prędkość: 25, // km/h
21  poziomAgresji: "Wysoki"
22};
23
24for (let parametr in limityBezpieczeństwa) {
25  if (tyranozaur[parametr] > limityBezpieczeństwa[parametr] || 
26      (parametr === "poziomAgresji" && tyranozaur[parametr] === "Bardzo wysoki")) {
27    console.log(`UWAGA: Parametr ${parametr} przekracza wartości bezpieczeństwa!`);
28  }
29}
30
31// Wynik:
32// UWAGA: Parametr waga przekracza wartości bezpieczeństwa!
33// UWAGA: Parametr prędkość przekracza wartości bezpieczeństwa!
34// UWAGA: Parametr poziomAgresji przekracza wartości bezpieczeństwa!

Ważna uwaga: Pętla

for...in
iteruje po wszystkich właściwościach obiektu, w tym dziedziczonych. Jeśli chcemy ograniczyć się tylko do własnych właściwości obiektu, możemy użyć metody
hasOwnProperty()
:

1for (let cecha in tyranozaur) {
2  if (tyranozaur.hasOwnProperty(cecha)) {
3    console.log(`${cecha}: ${tyranozaur[cecha]}`);
4  }
5}

Różnice między for...of i for...in

Ważne jest, aby zrozumieć różnicę między tymi dwoma typami pętli:

  • for...of - iteruje po wartościach elementów kolekcji (tablice, stringi, itp.)
  • for...in - iteruje po nazwach właściwości (kluczach) obiektu
1let dinosaurNames = ["T-Rex", "Raptor", "Triceratops"];
2
3// for...of (wartości)
4for (let name of dinosaurNames) {
5  console.log(name); // "T-Rex", "Raptor", "Triceratops"
6}
7
8// for...in (indeksy/klucze)
9for (let index in dinosaurNames) {
10  console.log(index); // "0", "1", "2"
11  console.log(dinosaurNames[index]); // "T-Rex", "Raptor", "Triceratops"
12}

Pętla while

Pętla

while
wykonuje blok kodu, dopóki określony warunek jest prawdziwy. W przeciwieństwie do pętli
for
, pętla
while
ma tylko warunek.

1// Struktura pętli while
2while (warunek) {
3  // Blok kodu do wykonania
4}

W Parku Jurajskim, pętla

while
może być używana do procesów, które nie mają z góry określonej liczby iteracji:

1// System monitorowania temperatury inkubatora jaj
2let temperatura = 37.5; // stopnie Celsjusza
3let docelowaTemperatura = 38.2;
4let przyrostTemperatury = 0.1;
5
6console.log("Rozpoczęcie procesu podgrzewania inkubatora...");
7
8while (temperatura < docelowaTemperatura) {
9  console.log(`Aktualna temperatura: ${temperatura.toFixed(1)}°C`);
10  temperatura += przyrostTemperatury;
11  // Kod do symulacji upływu czasu...
12}
13
14console.log(`Osiągnięto docelową temperaturę: ${temperatura.toFixed(1)}°C`);
15
16// System monitorowania poziomu zasilania
17let poziomZasilania = 100; // procent
18let krytycznyPoziom = 20;
19let spadekZasilania = 5;
20
21console.log("Monitorowanie poziomu zasilania po awarii głównego generatora...");
22
23while (poziomZasilania > krytycznyPoziom) {
24  console.log(`Poziom zasilania: ${poziomZasilania}%`);
25  poziomZasilania -= spadekZasilania;
26  // Kod do symulacji upływu czasu...
27}
28
29console.log(`ALARM! Krytyczny poziom zasilania: ${poziomZasilania}%`);
30console.log("Uruchamianie protokołu awaryjnego...");

Pętla do...while

Pętla

do...while
jest podobna do pętli
while
, ale z jedną kluczową różnicą: blok kodu jest zawsze wykonywany przynajmniej raz, zanim warunek zostanie sprawdzony.

1// Struktura pętli do...while
2do {
3  // Blok kodu do wykonania
4} while (warunek);

Ta pętla jest przydatna, gdy chcemy, aby kod został wykonany co najmniej raz, niezależnie od warunku:

1// Procedura uruchamiania systemu bezpieczeństwa
2let systemSprawny = false;
3let liczbaProb = 0;
4let maksymalnaLiczbaProb = 3;
5
6do {
7  console.log("Próba uruchomienia systemu bezpieczeństwa...");
8  liczbaProb++;
9  
10  // Symulacja losowości działania systemu
11  systemSprawny = Math.random() > 0.5; // 50% szans na sukces
12  
13  if (systemSprawny) {
14    console.log("System bezpieczeństwa uruchomiony pomyślnie!");
15  } else {
16    console.log(`Uruchomienie systemu nie powiodło się. Próba ${liczbaProb} z ${maksymalnaLiczbaProb}.`);
17  }
18  
19} while (!systemSprawny && liczbaProb < maksymalnaLiczbaProb);
20
21if (!systemSprawny) {
22  console.log("KRYTYCZNY BŁĄD: System bezpieczeństwa nie może zostać uruchomiony. Konieczna interwencja techniczna!");
23}
24
25// Procedura ewakuacji
26let pozostaliLudzie = 100;
27
28do {
29  console.log(`Pozostało ${pozostaliLudzie} osób do ewakuacji.`);
30  // Symulacja ewakuacji - każda iteracja to jedna grupa ewakuowanych
31  let wielkośćGrupy = Math.floor(Math.random() * 20) + 10; // 10-29 osób
32  pozostaliLudzie -= wielkośćGrupy;
33  
34  // Upewniamy się, że nie otrzymamy ujemnej liczby
35  if (pozostaliLudzie < 0) pozostaliLudzie = 0;
36  
37  console.log(`Ewakuowano grupę ${wielkośćGrupy} osób.`);
38  
39} while (pozostaliLudzie > 0);
40
41console.log("Wszyscy zostali ewakuowani. Obiekt jest pusty.");

Przerwanie i kontynuacja pętli: break i continue

JavaScript oferuje dwie specjalne instrukcje do kontrolowania przebiegu pętli:

  • break - natychmiast przerywa pętlę i wychodzi z niej
  • continue - przerywa bieżącą iterację i przechodzi do następnej

Przykład użycia break

1// Poszukiwanie uszkodzonej sekcji ogrodzenia
2let sekcjeOgrodzenia = [
3  { id: 1, status: "sprawna" },
4  { id: 2, status: "sprawna" },
5  { id: 3, status: "uszkodzona" },
6  { id: 4, status: "sprawna" },
7  { id: 5, status: "sprawna" }
8];
9
10let znalezionoUszkodzenie = false;
11
12for (let i = 0; i < sekcjeOgrodzenia.length; i++) {
13  console.log(`Sprawdzanie sekcji #${sekcjeOgrodzenia[i].id}...`);
14  
15  if (sekcjeOgrodzenia[i].status === "uszkodzona") {
16    console.log(`UWAGA! Znaleziono uszkodzoną sekcję #${sekcjeOgrodzenia[i].id}!`);
17    console.log("Wysyłanie zespołu naprawczego...");
18    znalezionoUszkodzenie = true;
19    break; // Przerywamy pętlę, gdy znaleźliśmy uszkodzenie
20  }
21}
22
23if (!znalezionoUszkodzenie) {
24  console.log("Wszystkie sekcje ogrodzenia są sprawne.");
25}
26
27// Wynik:
28// Sprawdzanie sekcji #1...
29// Sprawdzanie sekcji #2...
30// Sprawdzanie sekcji #3...
31// UWAGA! Znaleziono uszkodzoną sekcję #3!
32// Wysyłanie zespołu naprawczego...

Przykład użycia continue

1// Sprawdzanie stanu zdrowia dinozaurów, pomijając te, które są w trakcie badań
2let dinozaury = [
3  { nazwa: "Rex", gatunek: "Tyranozaur", dostępny: true },
4  { nazwa: "Blue", gatunek: "Velociraptor", dostępny: false }, // W trakcie badań
5  { nazwa: "Spike", gatunek: "Stegozaur", dostępny: true },
6  { nazwa: "Cera", gatunek: "Triceratops", dostępny: false }, // W trakcie badań
7  { nazwa: "Bronty", gatunek: "Brontozaur", dostępny: true }
8];
9
10console.log("Rozpoczęcie codziennych badań kontrolnych...");
11
12for (let i = 0; i < dinozaury.length; i++) {
13  if (!dinozaury[i].dostępny) {
14    console.log(`Dinozaur ${dinozaury[i].nazwa} (${dinozaury[i].gatunek}) jest już w trakcie badań. Pomijam.`);
15    continue; // Przechodzimy do następnej iteracji, pomijając resztę kodu w tej iteracji
16  }
17  
18  console.log(`Przeprowadzanie badania dinozaura ${dinozaury[i].nazwa} (${dinozaury[i].gatunek})...`);
19  console.log("Badanie zakończone. Stan zdrowia: dobry.");
20}
21
22// Wynik:
23// Rozpoczęcie codziennych badań kontrolnych...
24// Przeprowadzanie badania dinozaura Rex (Tyranozaur)...
25// Badanie zakończone. Stan zdrowia: dobry.
26// Dinozaur Blue (Velociraptor) jest już w trakcie badań. Pomijam.
27// Przeprowadzanie badania dinozaura Spike (Stegozaur)...
28// Badanie zakończone. Stan zdrowia: dobry.
29// Dinozaur Cera (Triceratops) jest już w trakcie badań. Pomijam.
30// Przeprowadzanie badania dinozaura Bronty (Brontozaur)...
31// Badanie zakończone. Stan zdrowia: dobry.

Pętle zagnieżdżone

Pętle mogą być także zagnieżdżane jedna w drugiej, co jest przydatne przy pracy z danymi wielowymiarowymi:

1// Sprawdzanie stanu ogrodzeń we wszystkich sektorach Parku Jurajskiego
2
3// Tablica dwuwymiarowa: [sektor][sekcja_ogrodzenia]
4let statusOgrodzeń = [
5  // Sektor 1
6  [
7    { id: "1A", stan: "sprawne" },
8    { id: "1B", stan: "sprawne" },
9    { id: "1C", stan: "uszkodzone" }
10  ],
11  // Sektor 2
12  [
13    { id: "2A", stan: "sprawne" },
14    { id: "2B", stan: "sprawne" },
15    { id: "2C", stan: "sprawne" }
16  ],
17  // Sektor 3
18  [
19    { id: "3A", stan: "sprawne" },
20    { id: "3B", stan: "uszkodzone" },
21    { id: "3C", stan: "sprawne" }
22  ]
23];
24
25console.log("Rozpoczęcie inspekcji ogrodzeń we wszystkich sektorach...");
26
27for (let i = 0; i < statusOgrodzeń.length; i++) {
28  console.log(`
29Inspekcja sektora ${i + 1}:`);
30  
31  let wszystkieSprawne = true;
32  
33  for (let j = 0; j < statusOgrodzeń[i].length; j++) {
34    let sekcja = statusOgrodzeń[i][j];
35    console.log(`  Sekcja ${sekcja.id}: ${sekcja.stan}`);
36    
37    if (sekcja.stan === "uszkodzone") {
38      wszystkieSprawne = false;
39      console.log(`  UWAGA: Sekcja ${sekcja.id} wymaga naprawy!`);
40    }
41  }
42  
43  if (wszystkieSprawne) {
44    console.log(`  Wszystkie ogrodzenia w sektorze ${i + 1} są sprawne.`);
45  } else {
46    console.log(`  W sektorze ${i + 1} wykryto uszkodzone ogrodzenia.`);
47  }
48}
49
50// Wynik:
51// Rozpoczęcie inspekcji ogrodzeń we wszystkich sektorach...
52//
53// Inspekcja sektora 1:
54//   Sekcja 1A: sprawne
55//   Sekcja 1B: sprawne
56//   Sekcja 1C: uszkodzone
57//   UWAGA: Sekcja 1C wymaga naprawy!
58//   W sektorze 1 wykryto uszkodzone ogrodzenia.
59//
60// Inspekcja sektora 2:
61//   Sekcja 2A: sprawne
62//   Sekcja 2B: sprawne
63//   Sekcja 2C: sprawne
64//   Wszystkie ogrodzenia w sektorze 2 są sprawne.
65//
66// Inspekcja sektora 3:
67//   Sekcja 3A: sprawne
68//   Sekcja 3B: uszkodzone
69//   UWAGA: Sekcja 3B wymaga naprawy!
70//   Sekcja 3C: sprawne
71//   W sektorze 3 wykryto uszkodzone ogrodzenia.

Pętle nieskończone i jak ich unikać

Pętla nieskończona to pętla, która nigdy się nie kończy, ponieważ jej warunek zakończenia nigdy nie jest spełniony. W Parku Jurajskim, pętla nieskończona w systemie bezpieczeństwa mogłaby prowadzić do katastrofy, podobnie jak w programowaniu może powodować zawieszenie aplikacji lub zużycie wszystkich zasobów.

Oto przykład pętli nieskończonej:

1// UWAGA: To jest pętla nieskończona! Nie uruchamiaj tego kodu!
2while (true) {
3  console.log("To się będzie wyświetlać w nieskończoność!");
4}
5
6// Inny przykład pętli nieskończonej:
7for (let i = 0; i >= 0; i++) {
8  console.log(i); // To będzie liczyć w nieskończoność!
9}

Aby uniknąć pętli nieskończonych:

  1. Upewnij się, że warunek zakończenia pętli jest osiągalny
  2. Zawsze aktualizuj zmienne używane w warunku pętli
  3. Rozważ dodanie dodatkowego warunku wyjścia (np. licznik iteracji)
  4. Używaj instrukcji
    break
    jako zabezpieczenia
1// Bezpieczniejsza wersja z limitem iteracji
2let maksymalnaLiczbaIteracji = 1000;
3let licznikIteracji = 0;
4
5// Przykład bezpiecznego monitorowania
6while (monitorujPark()) {
7  // Kod monitorowania parku...
8  
9  licznikIteracji++;
10  if (licznikIteracji >= maksymalnaLiczbaIteracji) {
11    console.log("Osiągnięto maksymalną liczbę iteracji. Przerwanie pętli.");
12    break;
13  }
14}
15
16function monitorujPark() {
17  // Logika monitorowania...
18  return true; // Normalnie zwracałoby true lub false w zależności od warunków
19}

Praktyki i wzorce związane z pętlami

1. Wybór odpowiedniej pętli

  • for - gdy znasz dokładną liczbę iteracji lub pracujesz z indeksami
  • for...of - gdy chcesz iterować po elementach kolekcji (tablice, stringi)
  • for...in - gdy chcesz iterować po właściwościach obiektu
  • while - gdy warunek zakończenia zależy od zewnętrznych czynników
  • do...while - gdy chcesz, aby kod wykonał się przynajmniej raz

2. Optymalizacja pętli

1// Nieoptymalna pętla - długość tablicy jest przeliczana w każdej iteracji
2for (let i = 0; i < dinozaury.length; i++) {
3  // Kod...
4}
5
6// Zoptymalizowana pętla - długość tablicy jest przeliczana tylko raz
7for (let i = 0, len = dinozaury.length; i < len; i++) {
8  // Kod...
9}

3. Wczesne wyjście z pętli

1// Wczesne wyjście z pętli po znalezieniu pierwszego pasującego elementu
2function znajdźDinozaura(nazwa) {
3  for (let dinozaur of bazaDinozaurów) {
4    if (dinozaur.nazwa === nazwa) {
5      return dinozaur; // Natychmiastowy zwrot po znalezieniu
6    }
7  }
8  return null; // Brak pasującego dinozaura
9}

4. Unikanie modyfikacji licznika pętli wewnątrz pętli

1// Niebezpieczne - modyfikowanie licznika wewnątrz pętli
2for (let i = 0; i < 10; i++) {
3  console.log(i);
4  if (i === 5) {
5    i = 8; // Przeskakujemy część iteracji - to może być mylące
6  }
7}
8
9// Lepsze podejście - użyj instrukcji continue lub break
10for (let i = 0; i < 10; i++) {
11  if (i > 5 && i < 9) {
12    continue; // Przeskakujemy iteracje 6, 7, 8
13  }
14  console.log(i);
15}

Podsumowanie

Pętle w JavaScript, podobnie jak rutynowe procedury w Parku Jurajskim, pozwalają na efektywne wykonywanie powtarzalnych operacji:

  1. for - do iteracji przez określoną liczbę powtórzeń
  2. for...of - do iteracji po elementach kolekcji
  3. for...in - do iteracji po właściwościach obiektu
  4. while - do wykonywania kodu, dopóki warunek jest prawdziwy
  5. do...while - do wykonywania kodu przynajmniej raz, a następnie dopóki warunek jest prawdziwy

Dodatkowo, instrukcje kontrolne:

  • break - przerywa całą pętlę
  • continue - przechodzi do następnej iteracji

Wybór odpowiedniej pętli zależy od konkretnego przypadku użycia, ale ogólnie należy dążyć do:

  • Używania najprostszej pętli odpowiedniej dla danego zadania
  • Optymalizowania pętli, szczególnie dla dużych kolekcji danych
  • Unikania pętli nieskończonych
  • Używania czytelnych nazw zmiennych i jasnej struktury kodu

W następnej lekcji przyjrzymy się funkcjom, które pozwalają na organizowanie kodu w wielokrotnie używalne bloki - niezbędne dla utrzymania porządku w tak złożonym systemie jak Park Jurajski.

Vai a CodeWorlds