Zamknięcia w ECMAScript

Najbardziej mylący aspekt ECMAScript to jego wsparcie dla zamknięć (closure).

Zamknięcie, to funkcja, która zawiera leksykalne wyrażenie, które nie jest obliczane, a która może używać zmiennych zdefiniowanych poza nią, to znaczy, że funkcja może używać zmiennych zdefiniowanych poza nią.

Prosty przykład zamknięcia

Użycie zmiennych globalnych w ECMAScript jest prostym przykładem zamknięcia. Pomyśl o poniższym kodzie:

var sMessage = "hello world";
function sayHelloWorld() {
  alert(sMessage);
}
sayHelloWorld();

W tym kodzie po załadowaniu skryptu do pamięci, zmienna sMessage nie jest obliczana dla funkcji sayHelloWorld(). Funkcja ta przechwytuje wartość sMessage tylko po to, aby użyć jej w przyszłości, co oznacza, że interpreter wie, że podczas wywoływania tej funkcji wartość sMessage musi być sprawdzona. Zmienna sMessage zostanie przypisana w momencie wywołania funkcji sayHelloWorld() (ostatni wiersz) i wyświetli wiadomość "hello world".

Złożony przykład zamknięcia

Definiowanie jednej funkcji wewnątrz innej sprawia, że zamknięcia stają się bardziej złożone. Na przykład:

var iBaseNum = 10;
function addNum(iNum1, iNum2) {
  function doAdd() {
    return iNum1 + iNum2 + iBaseNum;
  }
  return doAdd();
}

W tym miejscu funkcja addNum() zawiera funkcję doAdd() (zamknięcie). Wewnętrzna funkcja jest zamknięciem, ponieważ uzyskuje wartości parametrów i zmiennej globalnej iBaseNum z zewnętrznej funkcji. Ostatni krok funkcji addNum() polega na wywołaniu doAdd(), gdzie sumuje dwa parametry i zmienną globalną, zwracając ich sumę.

Kluczowym pojęciem do zrozumienia jest to, że funkcja doAdd() w ogóle nie przyjmuje parametrów, a wartości używa z otoczenia wykonywania.

Widać, że zamknięcia są bardzo silną i wszechstronną częścią ECMAScript, która może być używana do wykonywania złożonych obliczeń.

Wskazówka:Jak z każdym zaawansowanym funkcją, użycie zamknięć wymaga ostrożności, ponieważ mogą one stać się bardzo złożone.