Pytanie W JavaScript, jaka jest zaleta funkcji! () {} () Over (function () {}) ()? [duplikować]


Możliwe duplikaty:
Co oznacza wykrzyknik przed funkcją? 

Od dawna używane są następujące funkcje do samodzielnego wykonywania, anonimowe funkcje w JavaScript:

(function () { /* magic happens */ })()

Ostatnio zacząłem widzieć więcej przykładów następującego wzorca (np Bootstrap):

!function () { /* presumably the same magic happens */ }()

Czy ktoś wie, jaka jest przewaga drugiego wzoru? Czy to tylko stylistyczne preferencje?


76
2017-09-28 17:02


pochodzenie


Zobacz ten post wyjaśnia różnicę między tymi dwoma: stackoverflow.com/questions/3755606/... - Clive
W szczególności ta odpowiedź stackoverflow.com/questions/3755606/... - Michael Jasper
Powiedziałbym tę odpowiedź: stackoverflow.com/questions/3755606/... - Ivar Bonsaksen
Są one do tego celu (wymuszenie oceny funkcji w kontekst wyrażeń, nazywając to natychmiast ignorując jego wartość powrotu), ale IMHO I czuć że używanie Operator grupujący (nawiasy) to więcej "semantycznie poprawny" (i być może bardziej powszechne i czytelne również), bo takie są cel, powód tego operatora, oceniaj wyrażenia ... Tylko moje dwa centy ... Pozdrawiam! - CMS
Myślę, że to smutne, że to się zamknęło jako duplikat - to pytanie i wszystkie jego odpowiedzi są znacznie lepsze niż wszystko w duplikacie. - Skilldrick


Odpowiedzi:


Te dwie różne techniki mają funkcjonalność różnica jak również różnicę w wyglądzie. Potencjalne zalety jednej techniki względem drugiej będą wynikać z tych różnic.

Koniec

JavaScript to język, w którym concision może być bardzo ważne, ponieważ JavaScript jest pobrane po załadowaniu strony. Oznacza to, że im bardziej zwięzły jest JavaScript, tym szybszy czas pobierania. Z tego powodu istnieje Javascript minifiery i obfuscators kompresujące pliki Javascript w celu optymalizacji czasu pobierania. Na przykład spacje w alert ( "Hi" ) ; byłby zoptymalizowany pod kątem alert("Hi");.

Mając to na uwadze, porównaj te dwa wzory

  • Normalna zamknięcie: (function(){})()  16 znaków
  • Negacja zamknięcie: !function(){}()  15 znaków

Jest to w najlepszym razie mikro-optymalizacja, więc nie uważam tego za szczególnie przekonujący argument, chyba że robisz kod golfowy zawody.

Negowanie zwróconej wartości

Porównaj wartość wyniku a i b.

var a = (function(){})()
var b = !function(){}()

Od a funkcja niczego nie zwraca, a będzie undefined. Ponieważ negacja undefined jest true, b oceni na true. Jest to zaleta dla osób, które chcą albo zanegować zwróconą wartość funkcji, albo mieć fetysz wszystkiego, co trzeba zwrócić, a nie mieć wartości zerowej lub nieokreślonej. Możesz zobaczyć wyjaśnienie, jak to działa na ten temat inne pytanie związane z przepełnieniem stosu.

Mam nadzieję, że pomoże ci to zrozumieć uzasadnienie tej deklaracji funkcji, która zazwyczaj jest uważana za anty-wzór.


78
2017-09-28 17:11



Jeśli celem jest wykonanie tej funkcji (w ten sposób ją używam), to wracam undefined właściwie wydaje mi się bardziej poprawny. - Andrew Hedges
@AndrewHedges Zgodziłbym się. - Peter Olson
Dałem ci upominkę, ale mam problem z "podejrzliwością" ... - kennebec
Próba uczynienia kodu JavaScript słowem zwięzłym wydaje się być receptą na zamieszanie. Powinno być tak jasne, jak to tylko możliwe - samo istnienie tego pytania sprawia, że ​​jest oczywiste, że istnieje ogromna potrzeba klarowności kodu JS! Może zostać przekazany przez jeden z mininerów, do których odwołujesz się w ramach procesu budowania. - intuited
@intuited Right. Jak już powiedziałem, jest to prawdopodobnie bezużyteczna mikrooptymalizacja. Powiedział, że minifiery nie wykonają tego, ponieważ zmienia zachowanie funkcji i może spowodować złamanie kodu. - Peter Olson


Zawsze się wracam Utwór IIFE Ben Almana na takie pytania. To definitywne, o ile mi wiadomo.

Oto mięso artykuł:

// Either of the following two patterns can be used to immediately invoke
// a function expression, utilizing the function's execution context to
// create "privacy."

(function(){ /* code */ }()); // Crockford recommends this one
(function(){ /* code */ })(); // But this one works just as well

// Because the point of the parens or coercing operators is to disambiguate
// between function expressions and function declarations, they can be
// omitted when the parser already expects an expression (but please see the
// "important note" below).

var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();

// If you don't care about the return value, or the possibility of making
// your code slightly harder to read, you can save a byte by just prefixing
// the function with a unary operator.

!function(){ /* code */ }();
~function(){ /* code */ }();
-function(){ /* code */ }();
+function(){ /* code */ }();

// Here's another variation, from @kuvos - I'm not sure of the performance
// implications, if any, of using the `new` keyword, but it works.
// http://twitter.com/kuvos/status/18209252090847232

new function(){ /* code */ }
new function(){ /* code */ }() // Only need parens if passing arguments

51
2017-09-28 17:19



OOH nieźle. Nie widziałem tego. Dzięki! - Andrew Hedges
Ugh, javascript to bałagan. - BlueRaja - Danny Pflughoeft
JS nie jest bałaganem, jest dość mocny - ma tylko trochę mniejszą składnię punktów. ;) - Brian Arnold Sinclair
Z całą dodatkową składnią do zapamiętania (tak, prawda, na..do ... false..no, false, off), twierdzę, że CoffeeScript jest bardziej skomplikowanym skryptem Javascript. Chociaż CoffeeScript ma mniej znaków, nie jest prostsze. gist.github.com/1248911 - William
Zapisuje 1 bajt, ale myślę, że może to być również sprawa estetyczna. Nie sądzę, że ! jest ładny, ale myślę, że jest mniej brzydki niż zagnieżdżony ((){}()) Struktura... - Chris Burt-Brown


Wydaje się, że kluczową rzeczą jest to, że zasadniczo utrzymujesz parser z interpretacji funkcji jako deklaracji funkcji, a zamiast tego jest ona interpretowana jako anonimowe wyrażenie funkcji.

Używanie parens do grupowania wyrażenia lub używania! negowanie zwrotu to obie techniki wymiany parsowania. Następnie są natychmiast wywoływane przez następujące parens. Każda z tych form ma taki sam efekt netto pod tym względem, zakładając brak wyraźnej wartości zwrotu:

(function(){ /* ... */ })(); // Arguably most common form, => undefined
(function(){ /* ... */ }()); // Crockford-approved version, => undefined
!function(){ /* ... */ }();  // Negates the return, so => true
+function(){ /* ... */ }();  // Attempts numeric conversion of undefined, => NaN
~function(){ /* ... */ }();  // Bitwise NOT, => -1

Jeśli nie przechwytujesz zwróconej wartości, nie ma znaczącej różnicy. Można argumentować, że ~ może być szybszym opem, ponieważ jest to po prostu odbijanie bitów, a może! jest szybszym op, ponieważ jest to sprawdzanie prawdziwości / fałszu i zwracanie negacji.

Pod koniec dnia sposób, w jaki większość ludzi używa tego wzorca, polega na tym, że próbują przełamać nowy zakres, aby utrzymać porządek. Każda praca. Te ostatnie formy są popularne, ponieważ podczas gdy wprowadzają dodatkową (zazwyczaj niepotrzebną) operację, pomaga zaoszczędzić każdy dodatkowy bajt.

Ben Alman ma fantastyczny zapis na ten temat: http://benalman.com/news/2010/11/immediately-invoked-function-expression/


14
2017-09-28 17:21





Pierwszy "wzorzec" wywołuje funkcję anonimową (i jest wynikiem jej wartości zwracanej), podczas gdy drugi wywołuje funkcję anonimową i neguje jej wynik.

Czy o to pytasz? Oni robią nie Zrobić to samo.


4
2017-09-28 17:07





To jest prawie tylko preferencje stylistyczne, z wyjątkiem faktu, że ! zapewnia powrót funkcji (to znaczy zwraca true, z którego pochodzi !undefined).

Ponadto jest to o jeden znak mniej.


4
2017-09-28 17:10





Cóż w pierwszym przypadku, którego używasz ( ) aby owinąć obiekt, który chcesz wykonać, używając następnego zestawu (), aw następnym przypadku używasz operatora, który przyjmuje jeden argument (operator negacji!) i czynisz go domyślnie zawijając jego argument (funkcja) z ( ) więc faktycznie dostajesz !(function () { })(), wykonaj funkcję i zaneguj wynik, który zwraca. To może również działać z -, +, ~ na tej samej zasadzie, ponieważ wszyscy ci operatorzy przyjmują jeden argument.

!function () { /* presumably the same magic happens */ }()
-function () { /* presumably the same magic happens */ }()
+function () { /* presumably the same magic happens */ }()
~function () { /* presumably the same magic happens */ }()

Dlaczego chcesz to zrobić? Domyślam się, że jest to osobiste preferencje lub jeśli masz duży .JS i chcesz zapisać 1 znak na anonimowe wywołanie funkcji ...: D


1
2017-09-28 17:20