Forstå JavaScript-lukkinger i løkker: praktiske eksempler

JavaScript

Unraveling Loop Closures i JavaScript

JavaScript-utviklere møter ofte uventet oppførsel når de bruker lukkinger i løkker. Dette problemet kan føre til forvirring, spesielt for de som er nye i konseptet med nedleggelser.

I denne artikkelen skal vi utforske praktiske eksempler som illustrerer vanlige fallgruver og gir løsninger for å bruke lukkinger effektivt i løkker, enten det handler om hendelseslyttere, asynkron kode eller iterering over arrays.

Kommando Beskrivelse
let Erklærer en lokal variabel med blokkomfang, og initialiserer den eventuelt til en verdi. Brukes for å sikre at hver iterasjon av løkken har sitt eget omfang.
const Erklærer en blokk-omfanget, skrivebeskyttet navngitt konstant. Brukes til å lage en funksjon eller variabel hvis verdi ikke skal endres.
Promise Representerer den eventuelle fullføringen (eller feilen) av en asynkron operasjon og dens resulterende verdi.
setTimeout Kaller en funksjon eller evaluerer et uttrykk etter et spesifisert antall millisekunder.
addEventListener Fester en hendelsesbehandler til et spesifisert element uten å overskrive eksisterende hendelsesbehandlere.
IIFE Umiddelbart påkalt funksjonsuttrykk. En funksjon som kjører så snart den er definert. Brukes til å lage lokale scopes i loops.
for...in Itererer over de tallrike egenskapene til et objekt, i en vilkårlig rekkefølge.
for...of Itererer over verdiene til et gjentakbart objekt (som en matrise eller en streng), i en bestemt rekkefølge.

Forstå JavaScript-lukkinger i løkker

Skriptene i de foregående eksemplene tar for seg det vanlige problemet med lukkinger i løkker i JavaScript. Når du bruker en erklæring i en loop, deler alle iterasjoner samme funksjonsomfang. Dette er grunnen til, i det første eksemplet, utgangen er "Min verdi: 3" tre ganger. Løsningen er å bruke , som oppretter et blokkomfang som opprettholder riktig verdi for hver iterasjon. Denne tilnærmingen sikrer at hver iterasjon har sitt eget omfang, og dermed bevarer den riktige verdien når funksjonen kalles. Skriptet demonstrerer hvordan endre erklæringen fra til let retter opp problemet og logger "Min verdi: 0", "Min verdi: 1" og "Min verdi: 2" etter hensikten.

For asynkron kode kan det samme lukkingsproblemet oppstå. Ved hjelp av og funksjoner med sikrer at hver asynkron samtale opprettholder riktig iterasjonsverdi. Skriptet viser at ved å bruke wait med , logger hvert løst løfte den forventede verdien. Eventlyttere kan også møte lignende problemer; imidlertid å pakke inn lytterfunksjonen i en (Umiddelbart påkalt funksjonsuttrykk) hjelper til med å fange riktig verdi ved å opprette et nytt omfang for hver iterasjon. Bruken av og for...of loops demonstrerer videre viktigheten av scoping i lukkinger, og viser hvordan man korrekt fanger indeks og verdi ved å bruke for å lage distinkte omfang for hver loop-iterasjon.

Løse lukkeproblemer i JavaScript-løkker med 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]();
}

Sikre korrekte lukkeverdier i asynkron kode

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));
}

Riktig lukking i hendelseslyttere som bruker 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);
}

Riktig lukking med for ... inn og for ... av løkker

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();
}

Utforske bruken av lukkinger i avanserte JavaScript-funksjoner

Lukkinger er et grunnleggende konsept i JavaScript som lar en funksjon få tilgang til variabler fra det omsluttende omfanget, selv etter at omfanget er lukket. Denne funksjonen er spesielt kraftig når du oppretter avanserte funksjoner som de som brukes i memoization, currying og funksjonell programmering. Memoization utnytter for eksempel stenginger for å huske resultatene av dyre funksjonskall og returnere det hurtigbufrede resultatet når de samme inngangene skjer igjen. Ved å bruke lukkinger kan vi lage mer effektiv og optimalisert kode som forbedrer ytelsen, spesielt i rekursive funksjoner som beregning av Fibonacci-sekvenser.

En annen avansert bruk av lukkinger er å lage private variabler og funksjoner i JavaScript-objekter, simulere private metoder og egenskaper. Denne teknikken brukes ofte i modulmønstre og umiddelbart påkalte funksjonsuttrykk (IIFE) for å innkapsle funksjonalitet og unngå å forurense det globale omfanget. Dessuten spiller stenginger en avgjørende rolle i hendelseshåndtering og asynkron programmering, der de hjelper til med å beholde tilstand og kontekst over tid. Forståelse og effektiv bruk av nedleggelser kan heve dine JavaScript-programmeringsferdigheter betydelig og gjøre deg i stand til å skrive mer modulær, gjenbrukbar og vedlikeholdbar kode.

  1. Hva er en lukking i JavaScript?
  2. En lukking er en funksjon som beholder tilgang til sitt leksikale omfang, selv når funksjonen utføres utenfor dette omfanget.
  3. Hvorfor skjer lukkinger i løkker?
  4. Lukking i løkker oppstår fordi løkken oppretter funksjoner som fanger opp den samme variabelreferansen, noe som fører til uventet oppførsel hvis den ikke håndteres riktig.
  5. Hvordan kan vi fikse lukkingsproblemer i løkker?
  6. Ved hjelp av i stedet for i løkker eller ved hjelp av (Umiddelbart påkalte funksjonsuttrykk) kan fikse lukkingsproblemer ved å opprette et nytt omfang for hver iterasjon.
  7. Hva er en IIFE?
  8. An er en funksjon som utføres umiddelbart etter at den er opprettet, ofte brukt til å lage et nytt omfang og unngå variable konflikter.
  9. Kan lukkinger brukes i asynkron programmering?
  10. Ja, stenginger er avgjørende i asynkron programmering for å opprettholde tilstanden og konteksten på tvers av asynkrone operasjoner som løfter og tilbakeringinger.
  11. Hva er memoisering, og hvordan hjelper nedleggelser?
  12. Memoisering er en optimaliseringsteknikk for å bufre resultatene av dyre funksjonskall. Lukkinger hjelper ved å beholde tilgangen til hurtigbufferen på tvers av flere funksjonsanrop.
  13. Hvordan hjelper stenginger i hendelseshåndtering?
  14. Lukkinger beholder tilstanden til variablene som trengs av hendelsesbehandlere, og sikrer at de fungerer riktig når hendelsen utløses.
  15. Hva er modulmønsteret i JavaScript?
  16. Modulmønsteret bruker lukkinger for å lage private variabler og funksjoner, innkapsle funksjonalitet og unngå global forurensning.
  17. Kan nedleggelser simulere private metoder i JavaScript?
  18. Ja, nedleggelser kan simulere private metoder ved å holde variabler og funksjoner tilgjengelige bare innenfor funksjonens omfang der de er definert.

Å mestre lukkinger i JavaScript, spesielt innenfor loops, er avgjørende for å skrive forutsigbar og effektiv kode. Ved å utnytte , , og , kan utviklere unngå vanlige fallgruver og sikre korrekt variabel omfang. Denne forståelsen forbedrer evnen til å håndtere asynkrone oppgaver og hendelsesdrevet programmering, noe som til slutt fører til mer robuste applikasjoner.