kluczem do zrozumienia wzorców projektowych, takich jak IIFE, jest uświadomienie sobie, że przed ES6 JavaScript zawierał tylko zakres funkcji (a zatem nie zawierał zakresu bloków), przekazując wartości przez odniesienie wewnątrz zamknięć. Nie ma to już miejsca, ponieważ JavaScript w wersji ES6 implementuje zakresy bloków przy użyciu nowych słów kluczowych let
I const
.
Evaluation contextEdit
brak zakresu bloków oznacza, że zmienne zdefiniowane wewnątrz (na przykład) pętli for będą miały swoją definicję „podniesioną” na górze funkcji zamykającej. Obliczanie funkcji zależnej od zmiennych modyfikowanych przez funkcję zewnętrzną (w tym przez iterację) może być trudne. Możemy to zobaczyć bez pętli, jeśli zaktualizujemy wartość między zdefiniowaniem a wywołaniem funkcji.
var v, getValue;v = 1;getValue = function () { return v; };v = 2;getValue(); // 2
chociaż wynik może wydawać się oczywisty podczas ręcznej aktualizacjiv
, może on generować niezamierzone wyniki, gdygetValue()
jest zdefiniowany wewnątrz pętli.
następnie funkcja przekazuje v
jako argument i jest wywoływana natychmiast, zachowując wewnętrzny kontekst wykonania funkcji.
var v, getValue;v = 1;getValue = (function (x) { return function () { return x; };})(v);v = 2;getValue(); // 1
jest to odpowiednik następującego kodu:
var v, getValue;v = 1;function f(x) { return function () { return x; };};getValue = f(v);v = 2;getValue(); // 1
efektywny JavaScript Davida Hermana zawiera przykład ilustrujący problemy kontekstu ewaluacji wewnątrz pętli. Chociaż przykład Hermana jest celowo zawiły, wynika on bezpośrednio z tego samego braku zakresu bloku.
ustalanie prywatnych zmiennych i accessorsEdit
Iife są również przydatne do ustanawiania prywatnych metod dla dostępnych funkcji, jednocześnie ujawniając niektóre właściwości do późniejszego użycia. Poniższy przykład pochodzi z Alman ’ s post na IIFEs.
// "counter" is a function that returns an object with properties, which in this case are functions.var counter = (function () { var i = 0; return { get: function () { return i; }, set: function (val) { i = val; }, increment: function () { return ++i; } };})();// These calls access the function properties returned by "counter".counter.get(); // 0counter.set(3);counter.increment(); // 4counter.increment(); // 5
jeśli spróbujemy uzyskać dostęp docounter.i
ze środowiska globalnego, będzie on niezdefiniowany, ponieważ jest zamknięty w wywoływanej funkcji i nie jest właściwościącounter
. Podobnie, jeśli spróbujemy uzyskać dostęp do i
, spowoduje to błąd, ponieważ nie zadeklarowaliśmy i
w środowisku globalnym.