nyckeln till att förstå designmönster som IIFE är att inse att JavaScript före ES6 endast innehöll funktionsomfång (vilket saknar blockomfång), passerar värden genom referens inuti stängningar. Detta är inte längre fallet, eftersom ES6-versionen av JavaScript implementerar blockomfång med det nya let
och const
nyckelord.
Evaluation contextEdit
en brist på blockomfång innebär att variabler definierade inuti (till exempel) A för loop kommer att ha sin definition ”hissad” till toppen av den inneslutande funktionen. Att utvärdera en funktion som beror på variabler modifierade av den yttre funktionen (inklusive genom iteration) kan vara svårt. Vi kan se detta utan en slinga om vi uppdaterar ett värde mellan att definiera och åberopa funktionen.
var v, getValue;v = 1;getValue = function () { return v; };v = 2;getValue(); // 2
även om resultatet kan verka uppenbart när man uppdaterar v
manuellt kan det ge oavsiktliga resultat när getValue()
definieras inuti en slinga.
härefter passerar funktionen v
som ett argument och åberopas omedelbart och bevarar den inre funktionens exekveringskontext.
var v, getValue;v = 1;getValue = (function (x) { return function () { return x; };})(v);v = 2;getValue(); // 1
detta motsvarar följande kod:
var v, getValue;v = 1;function f(x) { return function () { return x; };};getValue = f(v);v = 2;getValue(); // 1
David Hermans effektiva JavaScript innehåller ett exempel som illustrerar problemen med utvärderingskontext i loopar. Medan Hermans exempel medvetet är invecklat, uppstår det direkt från samma brist på blockomfång.
upprätta privata variabler och accessorsEdit
IIFEs är också användbara för att upprätta privata metoder för tillgängliga funktioner samtidigt exponera vissa egenskaper för senare användning. Följande exempel kommer från Almans inlägg på 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
om vi försöker komma åt counter.i
från den globala miljön kommer den att vara odefinierad, eftersom den är innesluten i den anropade funktionen och inte är en egenskap av counter
. På samma sätt, om vi försöker komma åt i
, kommer det att resultera i ett fel, eftersom vi inte har deklarerat i
I den globala miljön.