W skrócie
Podsumowanie
W najprostszej formie technika ta ma na celu zawinięcie kodu w zakres funkcji .
Pomaga zmniejszyć szanse na:
- kolidowanie z innymi aplikacjami / bibliotekami
- zanieczyszczający lepszy (najprawdopodobniej globalny) zakres
To nie wykryć, gdy dokument jest gotowy - to nie jest jakaś document.onload
aniwindow.onload
Jest powszechnie znany jako Immediately Invoked Function Expression (IIFE)
lub Self Executing Anonymous Function
.
Kod wyjaśniony
var someFunction = function(){ console.log('wagwan!'); };
(function() { /* function scope starts here */
console.log('start of IIFE');
var myNumber = 4; /* number variable declaration */
var myFunction = function(){ /* function variable declaration */
console.log('formidable!');
};
var myObject = { /* object variable declaration */
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
})(); /* function scope ends */
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
W powyższym przykładzie każda zmienna zdefiniowana w funkcji (tj. Zadeklarowana za pomocą var
) będzie „prywatna” i dostępna TYLKO w zakresie funkcji (jak to ujęła Vivin Paliath). Innymi słowy, te zmienne nie są widoczne / osiągalne poza funkcją. Zobacz demo na żywo .
JavaScript ma zasięg funkcji. „Parametry i zmienne zdefiniowane w funkcji nie są widoczne poza funkcją, a zmienna zdefiniowana w dowolnym miejscu funkcji jest widoczna wszędzie w funkcji”. (z „Javascript: The Good Parts”).
Więcej szczegółów
Kod alternatywny
Ostatecznie kod opublikowany wcześniej można również wykonać w następujący sposób:
var someFunction = function(){ console.log('wagwan!'); };
var myMainFunction = function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
};
myMainFunction(); // I CALL "myMainFunction" FUNCTION HERE
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
Zobacz demo na żywo .
Korzenie
Iteracja 1
Pewnego dnia ktoś prawdopodobnie pomyślał „musi istnieć sposób na uniknięcie nazwania„ myMainFunction ”, ponieważ wszystko, czego chcemy, to natychmiastowe wykonanie”.
Jeśli wrócisz do podstaw, przekonasz się, że:
expression
: coś wartościującego. to znaczy3+11/x
statement
: Linia (y) kodu coś robią, ale to nie nie oceniają się do wartości. to znaczyif(){}
Podobnie wyrażenia funkcyjne są wartościowane. A jedną konsekwencją (zakładam?) Jest to, że można je natychmiast wywołać:
var italianSayinSomething = function(){ console.log('mamamia!'); }();
Nasz bardziej złożony przykład to:
var someFunction = function(){ console.log('wagwan!'); };
var myMainFunction = function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
}();
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
Zobacz demo na żywo .
Iteracja 2
Następnym krokiem jest myśl „ var myMainFunction =
po co, skoro nawet go nie używamy !?”.
Odpowiedź jest prosta: spróbuj to usunąć, na przykład poniżej:
function(){ console.log('mamamia!'); }();
Zobacz demo na żywo .
Nie zadziała, ponieważ „deklaracje funkcji nie są wywoływalne” .
Sztuką jest to, że poprzez usunięcie var myMainFunction =
my przekształcił wyrażenie funkcyjne w deklaracji funkcji . Więcej informacji na ten temat można znaleźć w linkach w „Zasobach”.
Następne pytanie brzmi: „dlaczego nie mogę zachować tego jako wyrażenia funkcji z czymś innym niż var myMainFunction =
?
Odpowiedź brzmi „możesz”, a tak naprawdę można to zrobić na wiele sposobów: dodając a +
, a !
, a -
lub owijanie w parę nawiasów (tak jak to obecnie odbywa się w konwencji) i więcej wierzę. Jako przykład:
(function(){ console.log('mamamia!'); })(); // live demo: jsbin.com/zokuwodoco/1/edit?js,console.
lub
+function(){ console.log('mamamia!'); }(); // live demo: jsbin.com/wuwipiyazi/1/edit?js,console
lub
-function(){ console.log('mamamia!'); }(); // live demo: jsbin.com/wejupaheva/1/edit?js,console
Po dodaniu odpowiedniej modyfikacji do tego, co było kiedyś naszym „Kodem alternatywnym”, wracamy do dokładnie tego samego kodu, który został użyty w przykładzie „Kod wyjaśniony”
var someFunction = function(){ console.log('wagwan!'); };
(function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
})();
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
Przeczytaj więcej o Expressions vs Statements
:
Demystifying Scopes
Można się zastanawiać: „co się stanie, gdy NIE zdefiniujesz zmiennej„ poprawnie ”w funkcji - tzn. Wykonasz proste przypisanie?
(function() {
var myNumber = 4; /* number variable declaration */
var myFunction = function(){ /* function variable declaration */
console.log('formidable!');
};
var myObject = { /* object variable declaration */
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
myOtherFunction = function(){ /* oops, an assignment instead of a declaration */
console.log('haha. got ya!');
};
})();
myOtherFunction(); // reachable, hence works: see in the console
window.myOtherFunction(); // works in the browser, myOtherFunction is then in the global scope
myFunction(); // unreachable, will throw an error, see in the console
Zobacz demo na żywo .
Zasadniczo, jeśli zmienna, która nie została zadeklarowana w swoim bieżącym zakresie, ma przypisaną wartość, wówczas „wyszukiwanie łańcucha zasięgu następuje, dopóki nie znajdzie zmiennej lub nie dotrze do zasięgu globalnego (w którym momencie ją utworzy)”.
W środowisku przeglądarki (w porównaniu ze środowiskiem serwera takim jak nodejs) zasięg globalny jest definiowany przez window
obiekt. Dlatego możemy to zrobić window.myOtherFunction()
.
Moja wskazówka „dobrych praktyk” na ten temat polega na tym, aby zawsze używać var
podczas definiowania czegokolwiek : niezależnie od tego, czy jest to liczba, obiekt czy funkcja, a nawet w zakresie globalnym. To znacznie upraszcza kod.
Uwaga:
- javascript nie ma
block scope
(Aktualizacja: zmienne lokalne zakresu bloków dodane w ES6 ).
- javascript ma tylko
function scope
& global scope
( window
zakres w środowisku przeglądarki)
Przeczytaj więcej o Javascript Scopes
:
Zasoby
Następne kroki
Po otrzymaniu tej IIFE
koncepcji prowadzi ona do tego module pattern
, co zwykle wykonuje się przez wykorzystanie tego wzoru IIFE. Baw się dobrze :)