Closures i JavaScript

Closures i JavaScript

Den här artikeln förklarar closures i JavaScript.

YouTube Video

Closures i JavaScript

I JavaScript är en 'closure' ett av de mycket viktiga och kraftfulla koncepten. Genom att förstå closures kan du få kunskap som är användbar i många situationer, som funktioners beteende och scope, samt JavaScripts asynkrona bearbetning och evenemangshantering. Här förklarar vi i detalj allt från den grundläggande definitionen av closures till konkreta exempel och deras tillämpningar.

Vad är en closure?

En closure syftar på mekanismen genom vilken en funktion kan komma åt variabler i sitt skapelsescope även när den anropas utanför detta scope. Genom att använda closures blir det möjligt för funktioner att kontinuerligt 'komma ihåg' externa variabler.

Closures består av följande två element.

  1. Funktionsdefinition (själva funktionen)

  2. Scopet där funktionen är definierad (variabler och andra funktioner utanför själva funktionen)

I JavaScript är closures möjliga eftersom funktioner har förmågan att komma åt variabler i det scope där de skapades.

Grundläggande exempel

Låt oss först titta på ett grundläggande exempel på en closure. I följande kod returnerar outerFunction en funktion som heter innerFunction. Det viktiga att notera är att innerFunction kan komma åt variabeln count som är definierad inom scopet för outerFunction.

 1function outerFunction() {
 2    let count = 0;
 3
 4    function innerFunction() {
 5        count++;
 6        console.log(`Current count: ${count}`);
 7    }
 8
 9    return innerFunction;
10}
11
12const counter = outerFunction();
13counter(); // Current count: 1
14counter(); // Current count: 2
15counter(); // Current count: 3

Hur closures fungerar

Som syns i ovan exempel, behålls count av innerFunction även efter att outerFunction har exekverats. innerFunction kan fortsätta att komma åt scopet för outerFunction och därför uppdateras count inom innerFunction. Detta är den grundläggande mekanismen för en closure.

Det är innerFunction som tilldelas variabeln counter, och vi kan se att tillståndet för count bevaras även om outerFunction redan har exekverats klart. Detta beror på att JavaScript kontinuerligt 'minns' scopet vid funktionsdefinitionstillfället.

Tillämpning: Closures som privata variabler

Closures kan användas som 'privata variabler' i objektorienterad programmering. Vanligtvis är objektens egenskaper i JavaScript direkt åtkomliga utifrån, men genom att använda closures är det möjligt att förhindra direkt manipulering av variabler inom funktionsscope utifrån.

I nästa exempel använder funktionen createCounter en closure för att skapa en räknare och returnerar en räknare med en privat variabel count.

 1function createCounter() {
 2    let count = 0;
 3
 4    return {
 5        increment: function() {
 6            count++;
 7            console.log(`Count: ${count}`);
 8        },
 9        decrement: function() {
10            count--;
11            console.log(`Count: ${count}`);
12        },
13        getCount: function() {
14            return count;
15        }
16    };
17}
18
19const myCounter = createCounter();
20myCounter.increment(); // Count: 1
21myCounter.increment(); // Count: 2
22myCounter.decrement(); // Count: 1
23console.log(myCounter.getCount()); // 1

I detta exempel finns count inom scopet för funktionen createCounter, så den kan inte kommas åt direkt utifrån. Dock kan den manipuleras via metoderna increment och decrement. På detta sätt kan du med closures införa konceptet privata variabler i JavaScript.

Praktiska exempel på closures

Kombination med callback-funktioner

Closures används ofta i kombination med callback-funktioner för att hantera asynkron bearbetning. Låt oss till exempel titta på ett exempel med en timer.

 1function startTimer(duration) {
 2    let timeLeft = duration;
 3
 4    function countdown() {
 5        console.log(`Time left: ${timeLeft} seconds`);
 6        timeLeft--;
 7
 8        if (timeLeft >= 0) {
 9            setTimeout(countdown, 1000);
10        }
11    }
12
13    countdown();
14}
15
16startTimer(5);
17// Time left: 5 seconds
18// Time left: 4 seconds
19// Time left: 3 seconds
20// Time left: 2 seconds
21// Time left: 1 second
22// Time left: 0 seconds

I detta exempel kommer funktionen countdown åt variabeln timeLeft inom scopet för startTimer. På detta sätt är closures mycket användbara för asynkron bearbetning som timers, då de behåller variablernas tillstånd över tid.

Eventhanterare

Closures är också praktiska när man sätter upp eventhanterare. I följande exempel används en closure för att registrera hur många gånger en knapp klickas på.

 1function setupClickCounter(buttonId) {
 2    let clickCount = 0;
 3
 4    const button = document.getElementById(buttonId);
 5    button.addEventListener('click', function() {
 6        clickCount++;
 7        console.log(`Button clicked ${clickCount} times`);
 8    });
 9}
10
11setupClickCounter('myButton');

I detta fall ökar clickCount för varje klick och dess värde behålls. Genom att använda closures kan du tilldela en oberoende räknare till varje knapp.

Slutsats

Closures är ett koncept som symboliserar flexibiliteten och styrkan i JavaScript. De behåller variabler inneslutna inom ett funktionsscope och möjliggör operationer på dessa variabler genom yttre åtkomliga funktioner. Genom att förstå och använda denna mekanism kan du förvärva mer avancerade tekniker inom JavaScript-programmering.

Closures tillämpas i olika situationer, från eventhantering och asynkron bearbetning till även pseudo-implementationer av objektorienterad programmering.

Du kan följa med i artikeln ovan med hjälp av Visual Studio Code på vår YouTube-kanal. Vänligen kolla även in YouTube-kanalen.

YouTube Video