funkcja javascript prowadząca bang! składnia


204

Widziałem tę składnię w kilku bibliotekach i zastanawiam się, jaka jest z tego korzyść. (uwaga: jestem świadomy zamknięć i tego, co robi kod, martwię się tylko różnicami składniowymi)

!function(){
  // do stuff
}();

Jako alternatywa dla bardziej powszechnych

(function(){
  // do stuff
})();

do samodzielnego wywoływania anonimowych funkcji.

Zastanawiam się kilka rzeczy. Po pierwsze, co pozwala na działanie najlepszego przykładu? Dlaczego huk jest konieczny, aby to stwierdzenie było poprawne pod względem składniowym? Powiedziano mi również, że to +działa i jestem pewien, że niektórzy zamiast tego!

Po drugie, jaka jest korzyść? Wszystko, co mogę powiedzieć, to to, że ratuje jedną postać, ale nie wyobrażam sobie, że jest to tak ogromna korzyść, aby przyciągnąć wielu adopcyjnych. Czy brakuje mi innej korzyści?

Jedyną inną różnicą, jaką widzę, byłaby wartość zwracana przez funkcję wywołującą, ale w obu tych przykładach tak naprawdę nie dbamy o wartość zwracaną przez funkcję, ponieważ służy ona jedynie do utworzenia zamknięcia. Czy ktoś może mi powiedzieć, dlaczego można zastosować pierwszą składnię?


Frameworki lubią zapisywać jak najwięcej znaków, których minimalizator nie może zoptymalizować.
alex

Pierwsza korzyść przychodzi mi na myśl, że możesz stworzyć piaskownicę, taką jak (function ($) {...}) (jQuery);
JS Taylor

2
oba przykłady osiągają to. Jak już wspomniano, rozumiem, co robią te funkcje, bardziej interesują mnie różnice składniowe
Brad

8
Przypisuję to potrzebie, by być uroczym w sposób bardziej wyrafinowany niż poprzednia załoga. „Och, mamy tych nawiasów pogańskich!”
Jared Farrish

2
Nigdy o tym nie wiedziałem, super. Podoba mi się, !ponieważ podkreśla, że ​​jest wykonywany.
cdmckay

Odpowiedzi:


97

Idealnie powinieneś być w stanie zrobić to wszystko po prostu jako:

function(){
  // do stuff
}(); 

Oznacza to, że zadeklaruj anonimową funkcję i uruchom ją. Ale to nie zadziała ze względu na specyfikę gramatyki JS.

Najkrótszą formą osiągnięcia tego jest użycie wyrażenia np. UnaryExpression (a więc CallExpression):

!function(){
  // do stuff
}(); 

Lub dla zabawy:

-function(){
  // do stuff
}(); 

Lub:

+function(){
  // do stuff
}(); 

Lub nawet:

~function(){
  // do stuff
  return 0;
}( );

3
więc jedyna korzyść zwięzła?
Brad

12
Dodałem wszystkie powyższe opcje do testu wydajności na stronie: jsperf.com/bang-function
Shaz

5
Ekspresyjność powiedziałbym. Prędkość nie ma tak naprawdę znaczenia w takich przypadkach, że działa raz.
c-smile

1
Z ciekawości zauważyłem, że żaden huk nie działa najszybciej, ale gdzieś w ewolucji Chrome, huk stał się szybszy niż brak huku. (Prawdopodobnie nieistotne statystycznie, ale ...) Czy istnieje powód, dla którego? Nie wiem dużo o kodzie pod maską, ale uważam, że jest to dość fascynujące.
jmk2142

Dwa z twoich jednoargumentowych operatorów mogą być interpretowane jako binarne, jeśli brakuje średnika. Pierwszy i ostatni są najbezpieczniejszymi z tych przykładów.

73

W języku Javascript wiersz rozpoczynający się od functionpowinien być instrukcją funkcji i powinien wyglądać

function doSomething() {
}

Funkcja samo-wywołująca się jak

function(){
  // do stuff
}();

nie pasuje do tej formy (i spowoduje błąd składniowy przy pierwszym otwierającym paren, ponieważ nie ma nazwy funkcji), więc nawiasy służą do określenia anonimowego wyrażenia funkcji .

(function(){
  // do stuff
})();

Ale zrobi wszystko, co tworzy wyrażenie (w przeciwieństwie do instrukcji funkcji), więc stąd !. Mówi tłumaczowi, że to nie jest instrukcja funkcji. Poza tym pierwszeństwo operatora narzuca, że ​​funkcja jest wywoływana przed negacją.

Nie byłem świadomy tej konwencji, ale jeśli stanie się powszechna, może przyczynić się do jej czytelności. Chodzi mi o to, że każdy, kto czyta !functionna górze dużego bloku kodu, spodziewa się samodzielnego wywołania, tak jak jesteśmy już uwarunkowani, aby oczekiwać tego samego, kiedy widzimy (function. Tyle że stracimy te irytujące nawiasy. Spodziewałbym się, że to jest powód, w przeciwieństwie do oszczędności prędkości lub liczby postaci.


Ta „linia zaczynająca się od funkcji jest oczekiwana ...” wygląda dość niewyraźnie. A co z tym:var foo = {CR/LF here} function bar() {}
c-smile

45

Oprócz rzeczy, które zostały już powiedziane, składnia z! jest przydatny, jeśli piszesz javascript bez średników:

var i = 1
!function(){
  console.log('ham')
}()

i = 2
(function(){
  console.log('cheese')
})()

Pierwszy przykład zwraca „ham” zgodnie z oczekiwaniami, ale drugi zgłosi błąd, ponieważ instrukcja i = 2 nie została zakończona z powodu następującego nawiasu.

Również w połączonych plikach javascript nie musisz się martwić, jeśli w poprzednim kodzie brakuje średników. Więc nie ma potrzeby wspólnego; (function () {}) (); aby upewnić się, że twoje własne się nie złamie.

Wiem, że moja odpowiedź jest trochę spóźniona, ale myślę, że jeszcze nie została wymieniona :)


6
+1 za wskazówkę i wspomnienia ... w dzisiejszych czasach nikt nie lubi pisać javascript bez średników.
Pablo Grisafi

4
Twitter Bootstrap to wszystko JS bez średników, i jest całkiem nowy ... (przepraszam, jeśli powyższy komentarz miał charakter sarkastyczny i spóźniłem się).
brandwaffle,

2
To nie jest tak naprawdę prawda. Rozważ następujący przykład:! Function () {console.log ("ham");} ()! Function () {console.log ("cheese")} (); pojawia się błąd: „Błąd składni: nieoczekiwany token!”
heavysixer

Tak masz rację. Wystąpił błąd, jeśli umieścisz je w tej samej linii. Nie myślałem o tym. Ale do tej pory nie robi tego żaden skrypt / lib konkatenacji. A kiedy minimalizujesz i konkatujesz pliki, dodajesz średniki. Tak więc, szczerze mówiąc, nie wyobrażam sobie przypadku, w którym wpadłbyś na ten problem. Z drugiej strony jest druga w
nocy

6

Po pierwsze, jsPerf pokazuje, że używanie !(UnaryExpression) jest zwykle szybsze. Czasem wyjdzie być równe, ale jeśli tak nie jest, ja nie widziałem non-waliły jeden triumf zbytnio nad innymi jeszcze: http://jsperf.com/bang-function

Zostało to przetestowane na najnowszym Ubuntu z najstarszym (powiedzmy ..) Chrome, wersja 8. Więc wyniki mogą się oczywiście różnić.

Edycja: A może coś szalonego delete?

delete function() {
   alert("Hi!"); 
}();

czy void?

void function() {
   alert("Hi!"); 
}();

ciekawy! Dostałem około 50/50, chociaż w Safari pod względem szybkości, niezmącona z pewnością miała swoją własną. Zastanawiam się, czy istnieje jakaś teoria potencjalnych różnic prędkości?
Brad

@brad Musi to mieć coś wspólnego z safari, jeśli spojrzysz na testy, większość innych przeglądarek wydaje się faworyzować !. Ale chciałbym też znaleźć teorię na ten temat :)
Shaz

3
Lubię void, ponieważ wyraźnie mówi „nie dbam o wartość zwracaną” i ponieważ przypomina mi konwencje w innych językach
code_monk

4

Jak widać tutaj , najlepszym sposobem na wykonywanie samodzielnie wywoływanych metod w javascript jest:

(function(){}()); -> 76,827,475 ops/sec

!function(){}();  -> 69,699,155 ops/sec

(function(){})(); -> 69,564,370 ops/sec

1
Wątpię, aby wydajność była powodem użycia jednej lub drugiej składni. Przy 70
mln operacji

3

Więc z negacją „!” i wszystkie inne jednoargumentowe operatory, takie jak +, -, ~, delete, void, wiele zostało powiedziane, aby podsumować:

!function(){
  alert("Hi!");
}(); 

Lub

void function(){
  alert("Hi!");
}();

Lub

delete function(){
  alert("Hi!");
}();

I jeszcze kilka przypadków z operatorami binarnymi dla zabawy :)

1 > function() {
   alert("Hi!"); 
}();

Lub

1 * function() {
   alert("Hi!"); 
}();

Lub

1 >>> function() {
   alert("Hi!"); 
}();

Lub nawet

1 == function() {
   alert("Hi!"); 
}();

Pozostawiając trójkę dla kogoś innego :)


12
0?0:function() { alert("Hi!"); }();
daniel1426

Bingo, Dan! Mamy
trójkę
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.