Que fait le point d'exclamation avant la fonction?


1242
!function () {}();

4
@Dykam Son utilité est expliquée dans cette réponse: stackoverflow.com/questions/5422585/…
hectorct



7
@befzz Mieux vaut se référer à cela comme une expression de fonction immédiatement invoquée, comme cet article l'expliquera plus tard ("l'auto-exécution" implique la récursivité)
Zach Esposito

Réponses:


2118

Syntaxe JavaScript 101. Voici une déclaration de fonction :

function foo() {}

Notez qu'il n'y a pas de point-virgule: c'est juste une déclaration de fonction . Vous auriez besoin d'une invocation foo()pour exécuter la fonction.

Maintenant, lorsque nous ajoutons le point d'exclamation apparemment inoffensif: !function foo() {}il le transforme en une expression . C'est maintenant une expression de fonction .

Le !seul n'invoque pas la fonction, bien sûr, mais nous pouvons maintenant mettre ()à la fin: !function foo() {}()qui a une priorité plus élevée que !et appelle instantanément la fonction.

Donc, ce que l'auteur fait, c'est enregistrer un octet par expression de fonction; une façon d'écrire plus lisible serait la suivante:

(function(){})();

Enfin, !rend l'expression return true. C'est parce que par défaut tous les retours IIFE undefined, ce qui nous laisse ce !undefinedqui est true. Pas particulièrement utile.


229
+1. C'est vraiment la meilleure réponse ici, et malheureusement, peu de votes positifs. Évidemment, !renvoie booléen, nous le savons tous, mais le grand point que vous faites est qu'il convertit également l'instruction de déclaration de fonction en une expression de fonction afin que la fonction puisse être immédiatement invoquée sans la mettre entre parenthèses. Pas évident, et clairement l'intention du codeur.
gilly3

64
+1 C'est la seule réponse qui traite réellement POURQUOI vous voudriez faire ceci, et pourquoi on le voit utilisé plus que la négation du résultat de retour semble justifier. L'opérateur unaire! (également ~, - et +) supprime toute ambiguïté d'une déclaration de fonction et permet aux parens à la fin () d'appeler la fonction en place. Cela est souvent fait pour créer une portée / un espace de noms local pour les variables lors de l'écriture de code modulaire.
Tom Auger

65
Un autre avantage est que! provoque une insertion de point-virgule, il est donc impossible que cette version soit concaténée à tort avec un fichier qui ne se termine pas par un;. Si vous avez le formulaire (), il le considérera comme un appel de fonction de tout ce qui a été défini dans le fichier précédent. Pointe du chapeau à un de mes collègues.
Jure Triglav

5
@Carnix var foo =brise l'ambiguïté de l'expression / expression et vous pouvez simplement écrire var foo = function(bar){}("baz");etc.
Neil

6
Cela se fait généralement par des scripts de minification / uglification, où chaque octet compte.
Dima Slivin

367

La fonction:

function () {}

ne renvoie rien (ou non défini).

Parfois, nous voulons appeler une fonction dès que nous la créons. Vous pourriez être tenté d'essayer ceci:

function () {}()

mais il en résulte un SyntaxError.

L'utilisation de l' !opérateur avant la fonction la traite comme une expression, nous pouvons donc l'appeler:

!function () {}()

Cela renverra également l'opposé booléen de la valeur de retour de la fonction, dans ce cas true, car !undefinedis true. Si vous souhaitez que la valeur de retour réelle soit le résultat de l'appel, essayez de le faire de cette façon:

(function () {})()

28
qui peut jamais en avoir besoin?
Andrey

13
c'est la seule réponse qui explique le cas dans la question, bravo!
Andrey

14
Votre deuxième exemple de code n'est pas un code JavaScript valide. Le but de !est de transformer la déclaration de fonction en une expression de fonction, c'est tout.
Skilldrick

8
@Andrey Le twitter bootstrap l'utilise dans tous les fichiers de plugin javascript (jQuery). Ajouter ce commentaire juste au cas où d'autres pourraient également avoir la même question.
Anmol Saraf

2
d3.js utilise également la !functionsyntaxe
Kristian

65

Il y a un bon point à utiliser !pour l'invocation de fonctions marqué sur le guide JavaScript airbnb

Idée générale pour utiliser cette technique sur des fichiers séparés (aka modules) qui seront ensuite concaténés. La mise en garde ici est que les fichiers sont censés être concaténés par des outils qui placent le nouveau fichier à la nouvelle ligne (ce qui est de toute façon un comportement courant pour la plupart des outils de concaténation). Dans ce cas, l'utilisation !aidera à éviter les erreurs dans le cas où le module précédemment concaténé manquerait un point-virgule de fin, et pourtant cela donnera la flexibilité de les mettre dans n'importe quel ordre sans souci.

!function abc(){}();
!function bca(){}();

Fonctionnera de la même manière que

!function abc(){}();
(function bca(){})();

mais enregistre un caractère et arbitraire semble mieux.

Et par la manière que ce soit +, -, ~, les voidopérateurs ont le même effet, en termes d'invoquer la fonction, bien sûr si vous devez utiliser quelque chose pour revenir de cette fonction , ils agiraient différemment.

abcval = !function abc(){return true;}() // abcval equals false
bcaval = +function bca(){return true;}() // bcaval equals 1
zyxval = -function zyx(){return true;}() // zyxval equals -1
xyzval = ~function xyz(){return true;}() // your guess?

mais si vous utilisez des modèles IIFE pour la séparation de code d'un module et d'un fichier et utilisez l'outil de concaturation pour l'optimisation (ce qui fait une tâche sur un seul fichier), alors la construction

!function abc(/*no returns*/) {}()
+function bca() {/*no returns*/}()

Réalisera l'exécution de code en toute sécurité, comme un tout premier exemple de code.

Celui-ci générera une erreur car JavaScript ASI ne pourra pas faire son travail.

!function abc(/*no returns*/) {}()
(function bca() {/*no returns*/})()

Une remarque concernant les opérateurs unaires, ils feraient un travail similaire, mais seulement au cas où, ils ne l'auraient pas utilisé dans le premier module. Ils ne sont donc pas si sûrs si vous n'avez pas un contrôle total sur l'ordre de concaténation.

Cela marche:

!function abc(/*no returns*/) {}()
^function bca() {/*no returns*/}()

Ce n'est pas:

^function abc(/*no returns*/) {}()
!function bca() {/*no returns*/}()

3
En fait, ces autres symboles n'ont pas le même effet. Oui, ils vous permettent d'appeler une fonction comme décrit, mais ils ne sont pas identiques. Considérez: var foo =! Function (bar) {console.debug (bar); }("chauve souris"); Peu importe lequel de vos symboles vous placez devant, vous obtenez "bat" dans votre console. Maintenant, ajoutez console.debug ("foo:", foo); - vous obtenez des résultats très différents en fonction du symbole que vous utilisez. ! force une valeur de retour qui n'est pas toujours souhaitable. Je préfère la syntaxe ({}) () pour plus de clarté et de précision.
Carnix

29

Il retourne si l'instruction peut évaluer false. par exemple:

!false      // true
!true       // false
!isValid()  // is not valid

Vous pouvez l'utiliser deux fois pour contraindre une valeur à booléenne:

!!1    // true
!!0    // false

Donc, pour répondre plus directement à votre question:

var myVar = !function(){ return false; }();  // myVar contains true

Edit: Cela a pour effet secondaire de changer la déclaration de fonction en une expression de fonction. Par exemple, le code suivant n'est pas valide car il est interprété comme une déclaration de fonction à laquelle il manque l' identifiant (ou nom de fonction ) requis :

function () { return false; }();  // syntax error

6
Par souci de clarté pour les lecteurs qui souhaitent utiliser une affectation avec une fonction immédiatement invoquée, votre exemple de code var myVar = !function(){ return false; }()pourrait omettre le !même var myVar = function(){ return false; }()et la fonction s'exécutera correctement et la valeur de retour ne sera pas modifiée.
Mark Fox

1
Pour être clair, vous pouvez l'utiliser une fois pour contraindre à booléen, car c'est un opérateur logique non . ! 0 = vrai et! 1 = faux. À des fins de minification JavaScript, vous souhaitez remplacer truepar !0et falsepar !1. Il enregistre 2 ou 3 caractères.
Triynko

9

C'est juste pour enregistrer un octet de données lorsque nous effectuons une minification javascript.

considérer la fonction anonyme ci-dessous

function (){}

Pour faire de ce qui précède une fonction auto-invoquante, nous changerons généralement le code ci-dessus comme

(function (){}())

Maintenant, nous avons ajouté deux caractères supplémentaires en (,)plus d'ajouter ()à la fin de la fonction ce qui était nécessaire pour appeler la fonction. Dans le processus de minification, nous nous concentrons généralement sur la réduction de la taille du fichier. Nous pouvons donc également écrire la fonction ci-dessus comme

!function (){}()

Les deux sont toujours des fonctions auto-appelantes et nous économisons également un octet. Au lieu de 2 caractères, (,)nous avons utilisé un seul caractère!


1
Ceci est utile car souvent vous le verrez dans js minifié
Pour le nom

5

! est un opérateur NOT logique , c'est un opérateur booléen qui inversera quelque chose à son opposé.

Bien que vous puissiez contourner les parenthèses de la fonction invoquée en utilisant le BANG (!) Avant la fonction, il inversera toujours le retour, ce qui n'est peut-être pas ce que vous vouliez. Comme dans le cas d'un IEFE, il retournerait indéfini , qui, lorsqu'il est inversé, devient le booléen true.

Utilisez plutôt la parenthèse fermante et le BANG ( ! ) Si nécessaire.

// I'm going to leave the closing () in all examples as invoking the function with just ! and () takes away from what's happening.

(function(){ return false; }());
=> false

!(function(){ return false; }());
=> true

!!(function(){ return false; }());
=> false

!!!(function(){ return false; }());
=> true

Autres opérateurs qui fonctionnent ...

+(function(){ return false; }());
=> 0

-(function(){ return false; }());
=> -0

~(function(){ return false; }());
=> -1

Opérateurs combinés ...

+!(function(){ return false; }());
=> 1

-!(function(){ return false; }());
=> -1

!+(function(){ return false; }());
=> true

!-(function(){ return false; }());
=> true

~!(function(){ return false; }());
=> -2

~!!(function(){ return false; }());
=> -1

+~(function(){ return false; }());
+> -1

5

Le point d'exclamation fait que toute fonction retourne toujours un booléen.
La valeur finale est la négation de la valeur retournée par la fonction.

!function bool() { return false; }() // true
!function bool() { return true; }() // false

Omettre !dans les exemples ci-dessus serait une SyntaxError .

function bool() { return true; }() // SyntaxError

Cependant, une meilleure façon d'y parvenir serait:

(function bool() { return true; })() // true

Ceci est une erreur. !change la façon dont le runtime analyse la fonction. Il oblige le runtime à traiter la fonction comme une expression de fonction (et non une déclaration). Il le fait pour permettre au développeur d'appeler immédiatement la fonction à l'aide de la ()syntaxe. !s'appliquera également (c'est-à-dire la négation) au résultat de l'invocation de l'expression de fonction.
Ben Aston

3

C'est une autre façon d'écrire IIFE (expression de fonction immédiatement invoquée).

Son autre façon d'écrire -

(function( args ) {})()

pareil que

!function ( args ) {}();

Eh bien, ce n'est pas exactement la même chose; la 2ème forme annule le résultat de l'appel de fonction (puis le jette, car il n'y a pas d'affectation de valeur). Je préférerais strictement la (function (args) {...})()syntaxe plus explicite et laisserais cette !functionforme aux outils de minification et d'obscurcissement.
Tobias

-1

! annulera (en face) tout ce que vous attendez en conséquence, c'est-à-dire si vous avez

var boy = true;
undefined
boy
true
!boy
false

lorsque vous appelez boy, votre résultat sera true, mais au moment où vous ajoutez le !lors de l'appel boy, c'est !boy-à- dire , votre résultat sera false. En d'autres termes, vous voulez dire NotBoy , mais cette fois, c'est essentiellement un résultat booléen, soit trueou false.

C'est la même chose qui arrive à l' !function () {}();expression, exécuter uniquement function () {}();vous signalera une erreur, mais ajouter !juste en face de votre function () {}();expression, en fait l'opposé de ce function () {}();qui devrait vous renvoyer true. Un exemple peut être vu ci-dessous:

function () {}();
SyntaxError: function statement requires a name
!function () {}();
true
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.