web-dev-qa-db-fra.com

En JavaScript, quel est l'avantage de! Fonction () {} () sur (fonction () {}) ()?

Dupliquer possible:
[.____] Que fait la marque d'exclamation avant la fonction?

J'ai longtemps utilisé ce qui suit pour les fonctions anonymes de l'exécution auto-exécutive dans JavaScript:

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

Dernièrement, j'ai commencé à voir plus d'instances du modèle suivant (par exemple, dans bootstrap ):

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

Quelqu'un sache quel avantage est du deuxième modèle? Ou, est-ce juste une préférence stylistique?

82
Andrew Hedges

Ces deux techniques différentes ont un différence ainsi qu'une différence d'apparence. Les avantages potentiels d'une technique sur l'autre seront dus à ces différences.

Concision

JavaScript est une langue où Concision peut être très important, car JavaScript est Téléchargé lorsque la page Charge. Cela signifie que plus le JavaScript est concis, Plus le temps de téléchargement. Pour cette raison, il existe JavaScript minifiers et Obfuscators Compressez les fichiers JavaScript pour optimiser le temps de téléchargement. Par exemple, les espaces de alert ( "Hi" ) ; seraient optimisés pour alert("Hi");.

Garder cela à l'esprit, comparez ces deux motifs

  • normal fermeture: (function(){})() 16 caractères
  • nié Fermeture: !function(){}() 15 caractères

Ceci est au mieux une micro-optimisation, donc je ne trouve pas cela un argument particulièrement convaincant que si vous faites un Code Golf Concours.

Nier la valeur retournée

Comparez la valeur de résultat de a et b.

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

Puisque la fonction a ne renvoie rien, a sera undefined. Depuis la négation de undefined is true, b va évaluer à true. Il s'agit d'un avantage des personnes qui souhaitent soit nier la valeur renvoyée de la fonction ou avoir une fétiche à valeur non nulle-null-ou non libellée. Vous pouvez voir une explication de la manière dont cela fonctionne sur ce fichier une autre question de dépassement de pile.

J'espère que cela vous aide à comprendre la justification de cette déclaration de fonction qui serait généralement considérée comme un anti-motif .

80
Peter Olson

Je suis toujours retourné sur la pièce de gloire de Ben Alman pour des questions comme celle-ci. C'est le définitif en ce qui me concerne.

Voici la viande de l'article :

// 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
53
Skilldrick

Il semble que la principale chose soit que vous gardez essentiellement l'analyseur d'interpréter la fonction en tant que déclaration de fonction, et il est d'être interprété comme une expression de fonction anonyme.

En utilisant les parens pour regrouper l'expression ou utiliser le! Pour nier le retour, il y a à la fois des techniques de modification de l'analyse. Il est ensuite immédiatement invoqué par les parens suivants. Toute et toutes ces formes ont le même effet net à cet égard, en supposant une valeur de retour explicite:

(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

Si vous ne capturez pas la valeur retournée, il n'y a pas de différence significative. On pourrait faire valoir que le ~ pourrait être un op plus rapide car il ne fait que retourner des bits, ou peut-être! est un op plus rapide puisqu'il s'agit d'un chèque véritable/faux et de retour de la négation.

À la fin de la journée, la façon dont la plupart des gens utilisent ce modèle est qu'ils essaient de briser un nouveau niveau de possibilité de garder les choses propres. Tout travail. Ces dernières formes sont populaires car elles introduisent une opération supplémentaire (typiquement inutile), économiser chaque octet supplémentaire aide.

Ben Alman a une fantastique ÉCRITUP sur le sujet: http://benalman.com/news/2010/11/IMMEDY-Invoked-fonctiond-expression/

14

Le premier "modèle" appelle la fonction anonyme (et résulte de sa valeur de retour) alors que la seconde appelle la fonction anonyme et nie son résultat.

Est-ce ce que vous demandez? Ils font pas faire la même chose.

4
Blindy

C'est presque Seule la préférence stylistique, à l'exception du fait que ! fournit une déclaration de fonction (c'est-à-dire renvoyer true, qui vient de !undefined).

En outre, c'est un caractère en moins.

4
doctorless

Eh bien, dans le premier cas, vous utilisez ( ) Pour envelopper l'objet que vous souhaitez exécuter avec l'ensemble suivant de (), Et dans le cas suivant que vous utilisez l'opérateur qui prend un argument (opérateur de négation !) Et vous le faites implicitement envelopper son argument (Funcion) avec ( ) Vous avez donc réellement !(function () { })(), exécutez la fonction et nier le résultat qu'elle revient. Cela peut également fonctionner avec -, +, ~ Dans le même principe, car tous les opérateurs prennent un 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 */ }()

Pourquoi voudriez-vous faire cela? Je suppose que c'est une préférence personnelle ou si vous avez de gros .js et souhaitez économiser 1 Char par une fonction anonyme ...: D

1
Cipi