Qual é o objetivo de uma função auto-executável em javascript?

427

Em javascript, quando você deseja usar isso:

(function(){
    //Bunch of code...
})();

por cima disto:

//Bunch of code...
Ej.
fonte
3
Também dê uma olhada em uma explicação ( técnica ) e aqui . Para a sintaxe, veja por que os parênteses são necessários e para onde devem ir .
Bergi 16/07/2014
Por que ele tem os dois últimos parênteses, pouco antes do ponto e vírgula?
johnny
3
@johnny a parte antes dos dois últimos parênteses declarar uma função (anônima). Esses dois parênteses chamam a função
Ej.
7
"Expressão da função chamada imediatamente" ou IIFE é um nome melhor para isso.
Flimm

Respostas:

404

É tudo sobre escopo variável. As variáveis ​​declaradas na função de execução automática, por padrão, estão disponíveis apenas para codificar na função de execução automática. Isso permite que o código seja gravado sem a preocupação de como as variáveis ​​são nomeadas em outros blocos de código JavaScript.

Por exemplo, conforme mencionado em um comentário de Alexander :

(function() {
  var foo = 3;
  console.log(foo);
})();

console.log(foo);

Isso primeiro registra 3e depois gera um erro no próximo, console.logporque foonão está definido.

Ken Browning
fonte
7
E também para o benefício de muitas pessoas por aí, incluindo um monte de engenheiros da Netflix: É APENAS UMA FUNÇÃO. Não é por si só representativo de um encerramento. Às vezes, os invocadores automáticos são usados ​​em conjunto com cenários relevantes para o fechamento para fazer coisas legais, mas se você não vê algo segurando uma referência que seria coletada no lixo e usada em uma linguagem que não seja de fechamento, não há nada a fazer. enlouquecendo com CLOSURES.
Erik Reppen
2
Então isso significa que é usado principalmente com fechamento?
22613 Pir
@AlexanderBird, não está bem ... se você ficar sem var, assim ...function(){ foo=3;}:? Isso definiria uma variável global, certo?
T.Todua
2
@AlexanderBird mas que já acontece em variáveis locais dentro de funções: function(){ var foo = 3; alert(foo); }; alert(foo);Então, eu ainda não entendo
João Pimentel Ferreira
Ah, entendi, você alcança todos esses três recursos ao mesmo tempo: 1) você executa a função apenas declarando-a; 2) Como qualquer função, o escopo das variáveis ​​é apenas local; e 3) A função pode ser anônima, não poluindo o escopo principal
João Pimentel Ferreira
94

Simplista. Tão muito normal, é quase reconfortante:

var userName = "Sean";

console.log(name());

function name() {
  return userName;
}

No entanto, e se eu incluir uma biblioteca javascript realmente útil na minha página que traduza caracteres avançados em suas representações no nível base?

Espere o que?

Quero dizer, se alguém digitar um personagem com algum tipo de sotaque, mas eu só quero caracteres em 'inglês' AZ no meu programa? Bem ... os caracteres espanhol 'ñ' e francês 'é' podem ser traduzidos para caracteres base de 'n' e 'e'.

Então, alguém legal escreveu um abrangente conversor de caracteres que eu posso incluir no meu site ... eu o incluo.

Um problema: ele tem uma função chamada 'name' igual à minha função.

Isso é chamado de colisão. Temos duas funções declaradas no mesmo escopo com o mesmo nome. Queremos evitar isso.

Então, precisamos escopo nosso código de alguma forma.

A única maneira de escopo do código em javascript é envolvê-lo em uma função:

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

Isso pode resolver o nosso problema. Agora tudo está fechado e só pode ser acessado de dentro de nossas chaves de abertura e fechamento.

Temos uma função em uma função ... que é estranha de se ver, mas totalmente legal.

Apenas um problema. Nosso código não funciona. Nossa variável userName nunca é ecoada no console!

Podemos resolver esse problema adicionando uma chamada à nossa função após o bloco de código existente ...

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

main();

Ou antes!

main();

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

Uma preocupação secundária: quais são as chances de o nome 'principal' ainda não ter sido usado? ... muito, muito magro.

Precisamos de mais escopo. E alguma maneira de executar automaticamente nossa função main ().

Agora chegamos às funções de execução automática (ou auto-executáveis, auto-executáveis, qualquer que seja).

((){})();

A sintaxe é estranha como o pecado. No entanto, funciona.

Quando você coloca uma definição de função entre parênteses e inclui uma lista de parâmetros (outro conjunto ou parênteses!), Ela atua como uma chamada de função .

Então, vejamos nosso código novamente, com alguma sintaxe auto-executável:

(function main() {
  var userName = "Sean";

    console.log(name());

    function name() {
      return userName;
    }
  }
)();

Portanto, na maioria dos tutoriais que você lê, agora você será bombardeado com o termo 'auto-execução anônima' ou algo semelhante.

Depois de muitos anos de desenvolvimento profissional, eu fortemente exortá-lo a nomear todas as funções que você escreve para fins de depuração.

Quando algo der errado (e ocorrerá), você verificará o backtrace no seu navegador. É sempre mais fácil restringir os problemas de código quando as entradas no rastreamento da pilha têm nomes!

Muito longo e espero que ajude!

Sean Holden
fonte
2
Obrigado :) Eu estava pesquisando na Internet o tempo todo, tentando entender as vantagens do IIFE em relação às funções normais em termos de privacidade variável e sua resposta é simplesmente a melhor. Todo mundo diz que uma das melhores vantagens é que as variáveis ​​e funções dentro do IIFE são 'finalmente' privadas quando uma função normal fornece exatamente a mesma coisa. Finalmente, acho que entendi o seu processo de explicação. Afinal, o IIFE é apenas uma função, mas agora eu entendo por que usá-lo.
viery365 20/09/16
Obrigado por reservar um tempo para explicar isso tão bem.
MSC
Boa resposta. Porém, eu tenho uma pergunta sobre o seu último ponto: quando você recomenda que todas as funções sejam nomeadas, você está dizendo que há uma maneira de fazer isso com funções de execução automática ou sugerindo que todos nomeiem a função e depois a chamem? EDIT Oh, entendo. Este já está nomeado. Duh. Pode-se salientar que você está justificando o uso de uma função auto-executável nomeada.
precisa saber é o seguinte
Bem, meu amigo, esta é a resposta que eu estava procurando:)
João Pimentel Ferreira
Esta é a resposta que eu estava procurando, não a que está marcada como aceita. Estou certo ao dizer que não se trata de colisão de nomes de variáveis , mas de colisão de nomes de funções ? Variáveis, mesmo em funções normais não-vida, têm escopo local e não colidem com variáveis ​​globais, não é?
Kumar Manish
32

A auto-invocação (também conhecida como auto-invocação) ocorre quando uma função é executada imediatamente após sua definição. Esse é um padrão central e serve como base para muitos outros padrões de desenvolvimento JavaScript.

Eu sou um grande fã :) disso porque:

  • Mantém o código no mínimo
  • Força a separação do comportamento da apresentação
  • Ele fornece um fechamento que evita conflitos de nomes

Enorme - (Por que você deveria dizer que é bom?)

  • É sobre definir e executar uma função de uma só vez.
  • Você pode fazer com que a função de execução automática retorne um valor e passe a função como um parâmetro para outra função.
  • É bom para encapsulamento.
  • Também é bom para o escopo do bloco.
  • Sim, você pode colocar todos os seus arquivos .js em uma função de execução automática e evitar a poluição global do espaço para nome. ;)

Mais aqui .

MA Hossain Tonu
fonte
43
Ponto 1. Como? Ponto 2. Isso é de uma prática recomendada completamente diferente. Ponto 3. Que função não funciona? 4,5,6,7. Relevância? 8. Bem, 1/8 não é ruim, eu acho.
Erik Reppen
2
Sete anos atrasado, mas, para o ponto 1., ele não reduz o código, na verdade, adiciona um mínimo de duas linhas de código na criação da função.
YungGun
1
O único ponto aqui é "Ele fornece um fechamento que evita conflitos de nomeação"; todos os outros pontos estão reformulando isso ou falso. talvez você possa simplificar sua resposta?
Pcarvalho 18/12/19
19

Namespacing. Os escopos do JavaScript são de nível de função.

Christoph
fonte
7
votos negativos ainda estão chegando porque eu usei namespacing instad de escopo ; isso é uma questão de definição - veja, por exemplo, Wikipedia : Um espaço para nome em ciência da computação (às vezes também chamado de escopo de nome), é um contêiner ou ambiente abstrato criado para armazenar um agrupamento lógico de identificadores ou símbolos exclusivos (ou seja, nomes). e Um identificador de espaço para nome pode fornecer contexto (Escopo em ciência da computação) a um nome, e os termos às vezes são usados ​​de forma intercambiável.
Christoph
5
Os escopos de nível de função do Javascript fornecem o espaço em que os nomes das variáveis ​​vivem, um espaço para nome ; que é um anônimo não associado com um identificador de namespace é irrelevante ...
Christoph
12

Não acredito que nenhuma das respostas menciona globais implícitas.

A (function(){})()construção não protege contra globais implícitas, o que para mim é a maior preocupação, consulte http://yuiblog.com/blog/2006/06/01/global-domination/

Basicamente, o bloco de funções garante que todos os "vars globais" dependentes que você definiu estejam confinados ao seu programa, não o protegem contra a definição de globais implícitos. JSHint ou similar pode fornecer recomendações sobre como se defender contra esse comportamento.

A var App = {}sintaxe mais concisa fornece um nível semelhante de proteção e pode ser agrupada no bloco de funções quando estiver em páginas 'públicas'. (consulte Ember.js ou SproutCore para obter exemplos reais de bibliotecas que usam essa construção)

No que diz respeito às privatepropriedades, elas são superestimadas, a menos que você esteja criando uma estrutura ou biblioteca pública, mas se precisar implementá-las, Douglas Crockford tem algumas boas idéias.

David W. Keith
fonte
8
O modo estrito protege contra globais implícitos. Isso, em conjunto com um invocador automático, você teria coberto. Eu nunca entendi a confusão sobre propriedades particulares. Declare vars dentro de um construtor func. Feito. Se o pensamento de esquecer de usar a palavra-chave 'new' mantém você acordado à noite, escreva uma função de fábrica. Feito novamente.
precisa saber é o seguinte
8

Eu li todas as respostas, algo muito importante está faltando aqui , eu vou BEIJAR. Existem 2 razões principais, pelas quais eu preciso de Funções Anônimas Autoexecutáveis ou, melhor dizendo, " Expressão de Função Imediatamente Invocada (IIFE) ":

  1. Melhor gerenciamento do espaço para nome (Evitando a poluição do espaço para nome -> Módulo JS)
  2. Encerramentos (simulação de membros da classe privada, como é conhecido no OOP)

O primeiro foi explicado muito bem. Para o segundo, estude o seguinte exemplo:

var MyClosureObject = (function (){
  var MyName = 'Michael Jackson RIP';
  return {
    getMyName: function () { return MyName;},
    setMyName: function (name) { MyName = name}
  }
}());

Atenção 1: Não estamos atribuindo uma função a MyClosureObject, mais ainda, o resultado de invocar essa função . Estar ciente de() última linha.

Atenção 2: O que você precisa saber adicionalmente sobre funções em Javascript é que as funções internas têm acesso aos parâmetros e variáveis das funções, elas são definidas dentro.

Vamos tentar algumas experiências:

Eu posso MyNameusar getMyNamee funciona:

 console.log(MyClosureObject.getMyName()); 
 // Michael Jackson RIP

A seguinte abordagem ingênua não funcionaria:

console.log(MyClosureObject.MyName); 
// undefined

Mas posso definir outro nome e obter o resultado esperado:

MyClosureObject.setMyName('George Michael RIP');
console.log(MyClosureObject.getMyName()); 
// George Michael RIP

Edit: No exemplo acima, ele MyClosureObjectfoi projetado para ser usado sem o newprefixo; portanto, por convenção, ele não deve ser capitalizado.

Solitário
fonte
7

Existe um parâmetro e o "Grupo de códigos" retorna uma função?

var a = function(x) { return function() { document.write(x); } }(something);

Fecho. O valor de somethingé usado pela função atribuída a a. somethingpode ter algum valor variável (para loop) e toda vez que uma tiver uma nova função.

stesch
fonte
+1; Eu prefiro uma explícita var x = something;na função exterior sobre xcomo parâmetro, no entanto: imo que é mais legível desta forma ...
Christoph
@Christoph: Se o valor de "alguma coisa" mudar após a criação da função, ele usará o novo valor e não o valor no momento de sua criação.
stesch
@stesch: de onde você tirou isso? Até onde eu sei, esse não é o caso; a única maneira de obter referências reais em JS é usando os argumentos de objeto, mas mesmo isso não funcionar em todos os navegadores
Christoph
@Christoph: "JavaScript: as boas partes", Douglas Crockford (O'Reilly)
stesch em 27/02/2009
@stesch: ele não funciona do jeito que você descrevê-lo: o novo valor será usado se você deixar cair a variável xe depende directamente do escopo léxico, ou seja document.write(something)...
Christoph
6

Isolamento do escopo, talvez. Para que as variáveis ​​dentro da declaração da função não poluam o espaço para nome externo.

É claro que, na metade das implementações de JS existentes, elas serão assim mesmo.

caos
fonte
4
Quais implementações seriam essas?
22415 Matthew Crumley
1
Qualquer implementação não gravada no modo estrito e contendo uma declaração var implícita e implícita que a torna global.
precisa
5

Aqui está um exemplo sólido de como uma função anônima auto-invocável pode ser útil.

for( var i = 0; i < 10; i++ ) {
  setTimeout(function(){
    console.log(i)
  })
}

Resultado: 10, 10, 10, 10, 10...

for( var i = 0; i < 10; i++ ) {
  (function(num){
    setTimeout(function(){
      console.log(num)
    })
  })(i)
}

Resultado: 0, 1, 2, 3, 4...

sg.cc
fonte
você pode explicar um pouco mais sobre o que está acontecendo para o primeiro conjunto de código
radio_head
No letlugar do varprimeiro caso, tudo ficará bem.
Vitaly Zdanevich 21/09/19
3

Uma diferença é que as variáveis ​​que você declara na função são locais, portanto desaparecem quando você sai da função e não entram em conflito com outras variáveis ​​em outro código.

Guffa
fonte
1

Como as funções em Javascript são objetos de primeira classe, definindo-o dessa maneira, ele define efetivamente uma "classe" como C ++ ou C #.

Essa função pode definir variáveis ​​locais e ter funções dentro dela. As funções internas (métodos de instância efetivamente) terão acesso às variáveis ​​locais (variáveis ​​de instância efetivamente), mas serão isoladas do restante do script.

James Curran
fonte
1

Função auto-invocada em javascript:

Uma expressão de auto-chamada é invocada (iniciada) automaticamente, sem ser chamada. Uma expressão auto-invocadora é invocada logo após ser criada. Isso é basicamente usado para evitar conflitos de nomes e para obter encapsulamento. As variáveis ​​ou objetos declarados não estão acessíveis fora desta função. Para evitar os problemas de minimização (filename.min), use sempre a função auto-executada.

Kishor Vitekar
fonte
1

A função de execução automática é usada para gerenciar o escopo de uma variável.

O escopo de uma variável é a região do seu programa em que está definida.

Uma variável global tem escopo global; ele é definido em qualquer lugar do seu código JavaScript e pode ser acessado de qualquer lugar do script, mesmo em suas funções. Por outro lado, variáveis ​​declaradas dentro de uma função são definidas apenas dentro do corpo da função. São variáveis ​​locais, têm escopo local e só podem ser acessadas nessa função. Os parâmetros da função também contam como variáveis ​​locais e são definidos apenas dentro do corpo da função.

Como mostrado abaixo, você pode acessar a variável variável global dentro de sua função e também observar que, no corpo de uma função, uma variável local tem precedência sobre uma variável global com o mesmo nome.

var globalvar = "globalvar"; // this var can be accessed anywhere within the script

function scope() {
    alert(globalvar);
    localvar = "localvar" //can only be accessed within the function scope
}

scope(); 

Então, basicamente, uma função de execução automática permite que o código seja escrito sem se preocupar com a forma como as variáveis ​​são nomeadas em outros blocos de código javascript.

Adeojo Emmanuel IMM
fonte
1
(function(){
    var foo = {
        name: 'bob'
    };
    console.log(foo.name); // bob
})();
console.log(foo.name); // Reference error

Na verdade, a função acima será tratada como expressão de função sem um nome.

O principal objetivo de agrupar uma função com parênteses próximos e abertos é evitar poluir o espaço global.

As variáveis ​​e funções dentro da expressão da função tornaram-se privadas (ie), não estarão disponíveis fora da função.

Madhankumar
fonte
1

A resposta curta é: para evitar a poluição do escopo Global (ou superior).

O IIFE (Expressões de Função Invocadas Imediatamente) é a melhor prática para escrever scripts como plug-ins, complementos, scripts de usuário ou qualquer outro script que possa funcionar com scripts de outras pessoas . Isso garante que qualquer variável que você defina não produza efeitos indesejados em outros scripts.

Essa é a outra maneira de escrever a expressão IIFE. Eu pessoalmente prefiro este método a seguir:

void function() {
  console.log('boo!');
  // expected output: "boo!"
}();

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void

A partir do exemplo acima, é muito claro que o IIFE também pode afetar a eficiência e o desempenho, porque a função que se espera que seja executada apenas uma vez será executada uma vez e depois despejada no vazio para sempre . Isso significa que a declaração de função ou método não permanece na memória.

Donovan P
fonte
Bom, eu nunca tinha visto esse uso voidantes. Eu gosto disso.
Ej.
1

Primeiro você deve visitar o MDN IIFE . Agora, alguns pontos sobre isso

  • esta é expressão de função chamada imediatamente . Portanto, quando seu arquivo javascript invocou do HTML, essa função foi chamada imediatamente.
  • Isso evita acessar variáveis ​​dentro do idioma IIFE, além de poluir o escopo global.
JustIn
fonte
0

Parece que esta pergunta já foi respondida, mas postarei minha opinião de qualquer maneira.

Sei quando gosto de usar funções auto-executáveis.

var myObject = {
    childObject: new function(){
        // bunch of code
    },
    objVar1: <value>,
    objVar2: <value>
}

A função permite que eu use algum código extra para definir os atributos e propriedades childObjects para um código mais limpo, como definir variáveis ​​usadas com frequência ou executar equações matemáticas; Oh! ou verificação de erro. em vez de se limitar à sintaxe de instanciação de objetos aninhados de ...

object: {
    childObject: {
        childObject: {<value>, <value>, <value>}
    }, 
    objVar1: <value>,
    objVar2: <value>
}

A codificação em geral tem muitas maneiras obscuras de fazer as mesmas coisas, fazendo você pensar: "Por que se preocupar?" Mas novas situações continuam surgindo, onde você não pode mais confiar apenas nos princípios básicos / principais.

Garrett
fonte
0

Dada a sua pergunta simples: "Em javascript, quando você deseja usar isso: ..."

Eu gosto das respostas de @ken_browning e @ sean_holding, mas aqui está outro caso de uso que não vejo mencionado:

let red_tree = new Node(10);

(async function () {
    for (let i = 0; i < 1000; i++) {
        await red_tree.insert(i);
    }
})();

console.log('----->red_tree.printInOrder():', red_tree.printInOrder());

onde Node.insert é alguma ação assíncrona.

Não posso simplesmente chamar em espera sem a palavra-chave assíncrona na declaração da minha função, e não preciso de uma função nomeada para uso posterior, mas preciso aguardar a chamada de inserção ou preciso de outros recursos mais ricos (quem sabe?) .

zentechinc
fonte
-3

IIRC permite criar propriedades e métodos privados.

Ólafur Waage
fonte