O que o ponto de exclamação faz antes da função?

1242
!function () {}();
Sebastian Otto
fonte
4
@Dykam Sua utilidade é explicada nesta resposta: stackoverflow.com/questions/5422585/…
hectorct
1
Nós chamá-lo auto-executar a função anônima ---
befzz
7
@befzz melhor para se referir a isso como uma expressão da função Imediatamente Chamado, em que este artigo explica depois ( "auto-executável" implica recursão)
Zach Esposito

Respostas:

2118

Sintaxe JavaScript 101. Aqui está uma declaração de função :

function foo() {}

Observe que não há ponto e vírgula: esta é apenas uma declaração de função . Você precisaria de uma chamada,, foo()para realmente executar a função.

Agora, quando adicionamos o ponto de exclamação aparentemente inócuo: !function foo() {}ele o transforma em uma expressão . Agora é uma expressão de função .

O !sozinho não invoca a função, é claro, mas agora podemos colocar ()no final: !function foo() {}()que tem maior precedência do que !e chama instantaneamente a função.

Então, o que o autor está fazendo é salvar um byte por expressão de função; uma maneira mais legível de escrever seria o seguinte:

(function(){})();

Por fim, !faz com que a expressão retorne verdadeira. Isso ocorre porque, por padrão, todo retorno IIFE undefined, o que nos deixa com o !undefinedque é true. Não é particularmente útil.

Neil
fonte
229
+1. Esta é realmente a melhor resposta aqui e, infelizmente, quase não foi votada. Obviamente,! retorna booleano, todos nós sabemos disso, mas o grande ponto a ser destacado é que ela também converte a declaração de declaração de função em uma expressão de função, para que a função possa ser chamada imediatamente sem colocá-la entre parênteses. Não é óbvio e claramente a intenção do codificador.
gilly3
64
+1 Esta é a única resposta que realmente aborda POR QUE você gostaria de fazer isso, e por que alguém o vê usado mais do que a negação do resultado do retorno parece justificar. O operador unário! (também ~, - e +) desambigua uma declaração de função e permite que os parênteses no final () invoquem a função no local. Isso geralmente é feito para criar um escopo / espaço de nome local para variáveis ​​ao escrever código modular.
Tom Auger
65
Outro benefício é esse! causa uma inserção de ponto-e-vírgula; portanto, é impossível que esta versão seja concatenada incorretamente com um arquivo que não termina com um;. Se você tiver o formulário (), consideraria uma chamada de função do que foi definido no arquivo anterior. Ponta do chapéu para um colega de trabalho meu.
Jure Triglav
5
@Carnix var foo =breaks a declaração / expressão ambigüidade e você pode simplesmente escrever var foo = function(bar){}("baz");etc.
Neil
6
Isso geralmente é feito por scripts de minificação / uglificação, onde cada byte conta.
Dima slivin
367

A função:

function () {}

não retorna nada (ou indefinido).

Às vezes, queremos chamar uma função da maneira que a criamos. Você pode ficar tentado a tentar o seguinte:

function () {}()

mas resulta em a SyntaxError.

Usar o !operador antes da função faz com que ela seja tratada como uma expressão, para que possamos chamá-la:

!function () {}()

Isso também retornará o oposto booleano do valor de retorno da função, neste caso true, porque !undefinedé true. Se você deseja que o valor de retorno real seja o resultado da chamada, tente fazer o seguinte:

(function () {})()
Michael Burr
fonte
28
quem pode precisar disso?
Andrey
13
esta é a única resposta que explica o caso da pergunta, bravo!
Andrey
14
Seu segundo exemplo de código não é JavaScript válido. O objetivo do !é transformar a declaração de função em uma expressão de função, só isso.
Skilldrick
8
@Andrey O twitter de bootstrap usa isso em todos os arquivos de plug-in javascript (jQuery). Adicionar este comentário apenas no caso de outras pessoas também terem a mesma pergunta.
Anmol Saraf
2
d3.js também usa a !functionsintaxe
Kristian
65

Há um bom ponto para usar !a chamada de função marcada no guia JavaScript do airbnb

Geralmente, a idéia de usar esta técnica em arquivos separados (também conhecidos como módulos) é concatenada posteriormente. A ressalva aqui é que os arquivos devem ser concatenados por ferramentas que colocam o novo arquivo na nova linha (que é um comportamento comum para a maioria das ferramentas concat). Nesse caso, o uso !ajudará a evitar erros no módulo se anteriormente concatenado perder o ponto e vírgula à direita, e ainda assim oferecerá a flexibilidade de colocá-los em qualquer ordem sem preocupações.

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

Funcionará da mesma forma que

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

mas salva um caractere e parece arbitrário melhor.

E pelo jeito qualquer um +, -, ~, voidos operadores têm o mesmo efeito, em termos de invocar a função, com certeza se você tem que usar algo para retornar de que a função agiriam de forma diferente.

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?

mas se você estiver usando padrões IIFE para uma separação de código de um arquivo e um módulo e usando a ferramenta concat para otimização (que faz um arquivo de uma linha e um trabalho), construção

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

Realizará a execução segura do código, o mesmo que um primeiro exemplo de código.

Este erro gerará porque o JavaScript ASI não poderá executar seu trabalho.

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

Uma observação sobre operadores unários, eles fariam um trabalho semelhante, mas apenas no caso, eles não usaram no primeiro módulo. Portanto, eles não são tão seguros se você não tiver controle total sobre a ordem de concatenação.

Isso funciona:

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

Isso não:

^function abc(/*no returns*/) {}()
!function bca() {/*no returns*/}()
dmi3y
fonte
3
Na verdade, esses outros símbolos não têm o mesmo efeito. Sim, eles permitem que você chame uma função como descrito, mas não são idênticos. Considere: var foo =! Function (bar) {console.debug (bar); }("bastão"); Independentemente de quais símbolos você colocar na frente, você recebe "bat" no seu console. Agora, adicione console.debug ("foo:", foo); - você obtém resultados muito diferentes com base no símbolo que você usa. ! força um valor de retorno que nem sempre é desejável. Prefiro a sintaxe ({}) () para maior clareza e precisão.
Carnix
29

Retorna se a instrução pode ser avaliada como falsa. por exemplo:

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

Você pode usá-lo duas vezes para coagir um valor a booleano:

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

Portanto, para responder mais diretamente à sua pergunta:

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

Editar: tem o efeito colateral de alterar a declaração da função para uma expressão de função. Por exemplo, o código a seguir não é válido porque é interpretado como uma declaração de função que está ausente do identificador necessário (ou nome da função ):

function () { return false; }();  // syntax error
gilly3
fonte
6
Por uma questão de clareza, para os leitores que desejarem usar uma atribuição com uma função chamada imediatamente, seu código de exemplo var myVar = !function(){ return false; }()pode omitir o !mesmo var myVar = function(){ return false; }()e a função será executada corretamente e o valor de retorno será intocado.
Mark Fox
1
Para ser claro, você pode usá-lo uma vez para coagir ao booleano, porque é um operador lógico, não . ! 0 = verdadeiro e! 1 = falso. Para fins de redução do JavaScript, você deve substituir truepor !0e falsecom !1. Ele salva 2 ou 3 caracteres.
Triynko 26/07/2015
9

É apenas para salvar um byte de dados quando fazemos minificação de javascript.

considere a função anônima abaixo

function (){}

Para fazer o que foi dito acima como função auto-invocável, geralmente alteraremos o código acima como

(function (){}())

Agora, adicionamos dois caracteres extras (,)além da adição ()no final da função, necessária para chamar a função. No processo de minificação, geralmente nos concentramos em reduzir o tamanho do arquivo. Então, também podemos escrever a função acima como

!function (){}()

Ainda assim, ambas são funções auto-invocáveis ​​e também salvamos um byte. Em vez de 2 caracteres, (,)usamos apenas um caractere!

Varatharaj
fonte
1
Isso é útil porque, muitas vezes, você vê isso em js minificado
Para o nome
5

! é um operador NÃO lógico , é um operador booleano que inverte algo para o seu oposto.

Embora você possa ignorar os parênteses da função chamada usando o BANG (!) Antes da função, ele ainda inverte o retorno, que pode não ser o que você queria. Como no caso de um IEFE, ele retornaria indefinido , que quando invertido se torna o verdadeiro booleano.

Em vez disso, use o parêntese de fechamento e o BANG ( ! ), Se necessário.

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

Outros operadores que trabalham ...

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

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

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

Operadores combinados ...

+!(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
SoEzPz
fonte
5

O ponto de exclamação faz com que qualquer função sempre retorne um valor booleano.
O valor final é a negação do valor retornado pela função.

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

Omitir !nos exemplos acima seria um SyntaxError .

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

No entanto, uma maneira melhor de conseguir isso seria:

(function bool() { return true; })() // true
oozzal
fonte
Isto está incorreto. !altera a maneira como o tempo de execução analisa a função. Faz com que o tempo de execução trate a função como uma expressão de função (e não uma declaração). Isso é feito para permitir que o desenvolvedor chame imediatamente a função usando a ()sintaxe. !também se aplicará (ou seja, negação) ao resultado da chamada da expressão da função.
Ben Aston
3

É outra maneira de escrever IIFE (expressão de função chamada imediatamente).

Sua outra maneira de escrever -

(function( args ) {})()

igual a

!function ( args ) {}();
Kamal
fonte
Bem, não é exatamente o mesmo; a segunda forma nega o resultado da chamada de função (e a joga fora, porque não há atribuição de valor). Eu preferiria estritamente a (function (args) {...})()sintaxe mais explícita e deixaria esse !functionformulário nas ferramentas de minificação e ofuscação.
Tobias
-1

! negará (oposto) o que você espera como resultado, ou seja, se você tiver

var boy = true;
undefined
boy
true
!boy
false

quando você ligar boy, seu resultado será true, mas no momento em que você adicionar o !quando ligar boy, ou seja !boy, seu resultado será false. O que, em outras palavras, você quer dizer NotBoy , mas desta vez é basicamente um resultado booleano, seja trueou false.

É a mesma coisa que acontece com a !function () {}();expressão: executar apenas function () {}();sinalizará um erro, mas será adicionado !à frente da sua function () {}();expressão, tornando o oposto do function () {}();que deve retornar você true. Exemplo pode ser visto abaixo:

function () {}();
SyntaxError: function statement requires a name
!function () {}();
true
antzshrek
fonte