Zrozumienie zamknięć JavaScript w pętlach: praktyczne przykłady

Zrozumienie zamknięć JavaScript w pętlach: praktyczne przykłady
Zrozumienie zamknięć JavaScript w pętlach: praktyczne przykłady

Odkrywanie domknięć pętli w JavaScript

Programiści JavaScriptu często spotykają się z nieoczekiwanym zachowaniem podczas używania zamknięć wewnątrz pętli. Problem ten może prowadzić do zamieszania, szczególnie dla tych, którzy nie mają pojęcia o zamknięciach.

W tym artykule przeanalizujemy praktyczne przykłady ilustrujące typowe pułapki i zapewniające rozwiązania umożliwiające efektywne wykorzystanie domknięć w pętlach, niezależnie od tego, czy mamy do czynienia z detektorami zdarzeń, kodem asynchronicznym czy iteracją po tablicach.

Komenda Opis
let Deklaruje zmienną lokalną o zasięgu blokowym, opcjonalnie inicjując ją wartością. Służy do zapewnienia, że ​​każda iteracja pętli ma swój własny zakres.
const Deklaruje stałą o zasięgu blokowym i tylko do odczytu. Służy do tworzenia funkcji lub zmiennej, której wartość nie powinna się zmieniać.
Promise Reprezentuje ostateczne zakończenie (lub niepowodzenie) operacji asynchronicznej i jej wynikową wartość.
setTimeout Wywołuje funkcję lub ocenia wyrażenie po określonej liczbie milisekund.
addEventListener Dołącza procedurę obsługi zdarzeń do określonego elementu bez zastąpienia istniejących procedur obsługi zdarzeń.
IIFE Natychmiast wywołane wyrażenie funkcyjne. Funkcja, która działa natychmiast po jej zdefiniowaniu. Służy do tworzenia lokalnych zakresów w pętlach.
for...in Iteruje po przeliczalnych właściwościach obiektu w dowolnej kolejności.
for...of Wykonuje iterację po wartościach obiektu iterowalnego (takiego jak tablica lub ciąg znaków) w określonej kolejności.

Zrozumienie zamknięć JavaScript w pętlach

Skrypty przedstawione w poprzednich przykładach rozwiązują typowy problem domknięć w pętlach w JavaScript. Podczas używania A var deklaracji w pętli, wszystkie iteracje mają ten sam zakres funkcji. Dlatego też w pierwszym przykładzie trzykrotnie zostanie wyświetlony komunikat „Moja wartość: 3”. Rozwiązaniem jest użycie let, co tworzy zakres blokowy, który zachowuje poprawną wartość dla każdej iteracji. Takie podejście zapewnia, że ​​każda iteracja ma swój własny zakres, zachowując w ten sposób poprawną wartość po wywołaniu funkcji. Skrypt pokazuje, jak zmienić deklarację z var Do let naprawia problem i rejestruje „Moja wartość: 0”, „Moja wartość: 1” i „Moja wartość: 2” zgodnie z zamierzeniami.

W przypadku kodu asynchronicznego może wystąpić ten sam problem z zamknięciem. Za pomocą Promises I setTimeout funkcjonuje z let zapewnia, że ​​każde wywołanie asynchroniczne utrzymuje poprawną wartość iteracji. Skrypt pokazuje to za pomocą wait z let, każda rozwiązana obietnica rejestruje oczekiwaną wartość. Słuchacze zdarzeń mogą również napotkać podobne problemy; jednakże zawijanie funkcji słuchacza w IIFE (Natychmiast wywołane wyrażenie funkcji) pomaga uchwycić poprawną wartość, tworząc nowy zakres dla każdej iteracji. Sposób użycia for...in I for...of pętle dodatkowo demonstruje znaczenie określania zakresu w domknięciach, pokazując, jak poprawnie przechwytywać indeks i wartość za pomocą IIFE aby utworzyć odrębne zakresy dla każdej iteracji pętli.

Rozwiązywanie problemów z zamykaniem w pętlach JavaScript za pomocą let

JavaScript (ES6)

let funcs = [];
// Let's create 3 functions
for (let i = 0; i < 3; i++) {
  // and store them in funcs
  funcs[i] = function() {
    // each should log its value.
    console.log("My value:", i);
  };
}
for (let j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

Zapewnienie poprawnych wartości zamknięcia w kodzie asynchronicznym

JavaScript (ES6)

const wait = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms));
for (let i = 0; i < 3; i++) {
  // Log `i` as soon as each promise resolves.
  wait(i * 100).then(() => console.log(i));
}

Prawidłowe zamknięcie w detektorach zdarzeń przy użyciu IIFE

JavaScript (ES6)

var buttons = document.getElementsByTagName("button");
// Let's create 3 functions
for (var i = 0; i < buttons.length; i++) {
  // as event listeners
  (function(i) {
    buttons[i].addEventListener("click", function() {
      // each should log its value.
      console.log("My value:", i);
    });
  })(i);
}

Prawidłowe zamknięcie za pomocą pętli for...in i for...of

JavaScript (ES6)

const arr = [1, 2, 3];
const fns = [];
for (const i in arr) {
  fns.push(((i) => () => console.log("index:", i))(i));
}
for (const v of arr) {
  fns.push(((v) => () => console.log("value:", v))(v));
}
for (const n of arr) {
  const obj = { number: n };
  fns.push(((n, obj) => () => console.log("n:", n, "|", "obj:", JSON.stringify(obj)))(n, obj));
}
for (const f of fns) {
  f();
}

Odkrywanie użycia zamknięć w zaawansowanych funkcjach JavaScript

Zamknięcia to podstawowe pojęcie w JavaScript, które umożliwia funkcji dostęp do zmiennych z otaczającego ją zakresu, nawet po zamknięciu tego zakresu. Ta funkcja jest szczególnie przydatna podczas tworzenia zaawansowanych funkcji, takich jak te używane do zapamiętywania, curry i programowania funkcjonalnego. Na przykład zapamiętywanie wykorzystuje domknięcia do zapamiętywania wyników kosztownych wywołań funkcji i zwracania wyników z pamięci podręcznej, gdy ponownie pojawią się te same dane wejściowe. Wykorzystując domknięcia, możemy stworzyć bardziej wydajny i zoptymalizowany kod, który zwiększa wydajność, szczególnie w funkcjach rekurencyjnych, takich jak obliczanie ciągów Fibonacciego.

Innym zaawansowanym zastosowaniem domknięć jest tworzenie prywatnych zmiennych i funkcji w obiektach JavaScript, symulując prywatne metody i właściwości. Technika ta jest często stosowana we wzorcach modułów i natychmiast wywoływanych wyrażeniach funkcyjnych (IIFE), aby hermetyzować funkcjonalność i unikać zanieczyszczania zasięgu globalnego. Co więcej, domknięcia odgrywają kluczową rolę w obsłudze zdarzeń i programowaniu asynchronicznym, gdzie pomagają zachować stan i kontekst w czasie. Zrozumienie i efektywne wykorzystanie domknięć może znacznie podnieść Twoje umiejętności programowania w JavaScript i umożliwić pisanie bardziej modułowego, wielokrotnego użytku i łatwiejszego w utrzymaniu kodu.

Często zadawane pytania dotyczące zamknięć JavaScript

  1. Co to jest zamknięcie w JavaScript?
  2. Zamknięcie to funkcja, która zachowuje dostęp do swojego zakresu leksykalnego, nawet jeśli funkcja jest wykonywana poza tym zakresem.
  3. Dlaczego domknięcia występują w pętlach?
  4. Zamknięcia pętli występują, ponieważ pętla tworzy funkcje, które przechwytują to samo odwołanie do zmiennej, co prowadzi do nieoczekiwanego zachowania, jeśli nie jest obsługiwane poprawnie.
  5. Jak możemy rozwiązać problemy z zamknięciem w pętlach?
  6. Za pomocą let zamiast var w pętlach lub używając IIFE (Natychmiast wywołane wyrażenia funkcyjne) mogą rozwiązać problemy z zamknięciem, tworząc nowy zakres dla każdej iteracji.
  7. Co to jest IIFE?
  8. Jakiś IIFE to funkcja wykonywana natychmiast po jej utworzeniu, często używana do utworzenia nowego zakresu i uniknięcia konfliktów zmiennych.
  9. Czy domknięcia mogą być używane w programowaniu asynchronicznym?
  10. Tak, domknięcia są niezbędne w programowaniu asynchronicznym, aby utrzymać stan i kontekst w operacjach asynchronicznych, takich jak obietnice i wywołania zwrotne.
  11. Co to jest zapamiętywanie i jak pomagają zamknięcia?
  12. Zapamiętywanie to technika optymalizacji polegająca na buforowaniu wyników kosztownych wywołań funkcji. Zamknięcia pomagają zachować dostęp do pamięci podręcznej podczas wielu wywołań funkcji.
  13. W jaki sposób zamknięcia pomagają w obsłudze zdarzeń?
  14. Zamknięcia zachowują stan zmiennych potrzebnych procedurom obsługi zdarzeń, zapewniając ich prawidłowe działanie po wyzwoleniu zdarzenia.
  15. Jaki jest wzór modułu w JavaScript?
  16. Wzorzec modułu wykorzystuje domknięcia do tworzenia prywatnych zmiennych i funkcji, hermetyzując funkcjonalność i unikając zanieczyszczenia zasięgu globalnego.
  17. Czy zamknięcia mogą symulować metody prywatne w JavaScript?
  18. Tak, domknięcia mogą symulować metody prywatne, utrzymując zmienne i funkcje dostępne tylko w zakresie funkcji, w której są zdefiniowane.

Ostatnie przemyślenia na temat zamknięć JavaScript w pętlach

Opanowanie domknięć w JavaScript, szczególnie w pętlach, jest kluczowe dla pisania przewidywalnego i wydajnego kodu. Poprzez wykorzystanie let, Promises, I IIFE, programiści mogą uniknąć typowych pułapek i zapewnić prawidłowe określanie zakresu zmiennych. To zrozumienie zwiększa zdolność do obsługi zadań asynchronicznych i programowania sterowanego zdarzeniami, co ostatecznie prowadzi do bardziej niezawodnych aplikacji.