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.onloadaniwindow.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 windowobiekt. Dlatego możemy to zrobić window.myOtherFunction().
Moja wskazówka „dobrych praktyk” na ten temat polega na tym, aby zawsze używać varpodczas 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( windowzakres w środowisku przeglądarki)
Przeczytaj więcej o Javascript Scopes:
Zasoby
Następne kroki
Po otrzymaniu tej IIFEkoncepcji prowadzi ona do tego module pattern, co zwykle wykonuje się przez wykorzystanie tego wzoru IIFE. Baw się dobrze :)