o que é
No JavaScript, cada função, quando chamada, cria um novo contexto de execução. Como as variáveis e funções definidas nas funções são as únicas variáveis que são acessadas internamente, não externamente, ao chamar uma função, o contexto fornecido pela função fornece uma maneira muito simples de criar variáveis privadas.
function makecounter () {var i = 0; retornar function () {console.log (++ i); }; } // Lembre -se: `contador` e` contra2` têm suas próprias variáveis `i`var contador = makecounter (); contador (); // 1Counter (); // 2var contador2 = makecounter (); contador2 (); // 1Counter2 () // 2i;Em muitos casos, você pode não precisar de uma função como o MakeWhathy para retornar vários valores acumulados, e você pode chamá -lo apenas uma vez para obter um único valor e, em alguns outros casos, você nem precisa conhecer o valor de retorno explicitamente.
Seu núcleo
Agora, não importa, você define uma função como função foo () {} ou var foo = function () {}, ao ligar, você precisa adicionar um par de parênteses depois dela, como foo ().
// A função definida abaixo pode ser chamada adicionando um par de colchetes após o nome da função, como `foo ()`, // porque foo é apenas uma variável de referência var foo = function () {/ * code */} `relativa à expressão da função` funcce () {/ * code */} `` `` `` `` `` `” `` ””, que pode ser mostrado, então, a expressão de uma função '/ */{ */} ``} `` `` funcor */{ */ */} ``} `` `funcl. Depois disso? function () { / * code * /} (); // SyntaxError: token inesperado (Como você pode ver, um bug é capturado aqui. Quando parênteses aparecem por trás de uma função para chamar uma função, se você encontrar uma palavra -chave de função no ambiente global ou no ambiente local, por padrão, ela a tratará como uma declaração de função e não uma expressão de função. Se você não informar explicitamente aos parênteses que é uma expressão, ele a tratará como uma função sem um nome e lançará um erro, porque a declaração de função requer um nome.
Pergunta 1: Posso pensar em uma pergunta aqui? Podemos também chamar a função var foo = function () {console.log (1)} () diretamente assim, e a resposta está ok.
Pergunta 2: Da mesma forma, também podemos pensar em uma pergunta. Se uma declaração de função como essa é chamada diretamente com parênteses, o que acontece? Por favor, veja a resposta abaixo.
Função, parênteses, erro
Curiosamente, se você especificar um nome para uma função e colocar um par de parênteses por trás, o mesmo erro será lançado, mas desta vez é por outro motivo. Quando parênteses são colocados após uma expressão de função, indica que essa é uma função chamada e os parênteses são colocados após uma declaração, significa que eles estão completamente separados da declaração de função anterior. No momento, os parênteses são apenas uma representação simples de parênteses (aparelhos usados para controlar a prioridade da operação).
//No entanto, a declaração da função é sintaticamente inválida, ainda é uma declaração e os seguintes parênteses são inválidos, porque os parênteses precisam incluir a função de expressão foo () {/* code*/} (); // syntaxError: inesperado, mas a função agora, você coloca uma expressão nos pátios */} (1) // é equivalente ao seguinte, uma declaração de função segue uma expressão que não tem nenhum relacionamento: function foo () {/ *code */} (1);Executar expressões de função imediatamente (iife)
Felizmente, é fácil corrigir erros gramaticais. O método mais popular e mais aceito é envolver declarações de função entre parênteses para dizer ao analisador para expressar uma expressão de função, porque no JavaScript, os parênteses não podem conter declarações. Por esse motivo, quando os parênteses encontram a palavra -chave da função para envolver a função, ele sabe analisá -la como uma expressão de função em vez de uma declaração de função. Preste atenção ao entendimento de que os parênteses aqui são diferentes dos parênteses acima quando encontram funções, ou seja,
Quando parênteses aparecem no final de uma função anônima e desejam chamar uma função, ela padrão tratará a função como uma declaração de função.
Ao envolver uma função entre parênteses, ele analisará a função como uma expressão por padrão, em vez de declarar a função.
// Ambos os padrões podem ser usados para chamar uma expressão de função imediatamente, usando a execução da função para criar variáveis privadas (function () {/ * code */} ()); // Crockford recomenda esta, a expressão entre colchetes representa a função imediatamente (function () {/ * code */}) (); //, mas essa obra apenas como uma pessoa, apenas () {/ * code */}); Os operadores de coagir devem desambiguar // entre expressões de função e declarações de funções, eles podem ser // omitidos quando o analisador já espera uma expressão (mas consulte // "nota importante" abaixo) .Var i = function () {return 10;} (); true && function) {/*code*/} (); Legável possível, você pode armazenar bytes levando um operador unário na frente de sua função! function () {/ * code */} (); ~ function () {/ * code */} (); - function () {/ * code */} ();+function () {/ * code */} (); // aqui está outra variação, de @kuvos - não tenho certeza da performance // implicações, se é que qualquer outra http://twitter.com/kuvos/status/18209252090847232New function () {/ * code */} new function () {/ * code */} () // só precisa de parens se passar argumentos de passagemNotas importantes sobre colchetes
Em alguns casos, não é necessário envolver a expressão da função quando colchetes ambíguos adicionais estão em torno da expressão da função (porque os colchetes já são expressos como uma expressão), mas essa ainda é uma boa idéia quando os colchetes são usados para chamar a expressão da função.
Esses colchetes indicam que a expressão da função será chamada imediatamente e que a variável armazenará o resultado da função, não a própria função. Quando essa é uma expressão de função muito longa, isso economiza tempo do que as pessoas que lêem seu código sem precisar rolar para a parte inferior da página para ver se a função é chamada.
Como regra, quando você escreve código claro e claro, é necessário impedir que o JavaScript ligue erros, e também é necessário impedir que outros desenvolvedores joguem erros para você Wtferror!
Salve o status do fechamento
Assim como quando uma função é chamada pelo nome, os parâmetros são passados e, quando a expressão da função é chamada imediatamente, os parâmetros são passados. Uma expressão de função imediatamente chamada pode ser usada para bloquear os valores e salvar efetivamente o estado neste momento, porque qualquer função definida em uma função pode usar parâmetros e variáveis passadas pela função externa (esse relacionamento é chamado de fechamento).
// Pode não funcionar como você pensa, porque o valor de `eu 'nunca está bloqueado. // inversamente, quando cada link é clicado (o loop foi executado bem), portanto, o número total de todos os elementos aparecerá, // porque esse é o valor verdadeiro de `i` no momento. var elems = document.getElementsByTagName ('a'); para (var i = 0; i <eMems.length; i ++) {elems [i] .AddeventListener ('clique', function (e) {e.PreventDefault (); e alert ('i am link #'+ i)}, false); `I` Valor está bloqueado em` LockedInindex`. // Quando o loop é executado, embora o valor numérico do valor `i` seja a soma de todos os elementos, toda vez que a expressão da função é chamada, o valor` LockedInindex` no IIFE é o valor transmitido a ele por `i`, então quando o link é clicado, o valor correto é exibido. var elems = document.getElementsByTagName ('a'); para (var i = 0; i <elems.length; i ++) {(function (LockedInindex) {elems [i] .AdDeventListener ('click', function (e) {e.PreventDefault (); ALERT ('iMiM (' iM link ', Function (e) {e.PreventDefault (); ALERT (' iMiM ('iM link', Function (e) {e.PreventDefault (); ALERT ('iMiM (', 'Link', link ', e). }) (i);} // Você também pode usar o IIFE como o seguinte, apenas usando parênteses para incluir a função de processamento de cliques e não incluir todo o `addEventListener`. // Não importa de que maneira, ambos os exemplos podem ser bloqueados com o IIFE, mas achei que o exemplo anterior é mais legível var elems = document.getElementsByTagName ('a'); para (var i = 0; i <eMems.length; i ++) {elems [i] .AdDeventListener ('click' (function; alerta ('eu sou link #' + LockedInIndex); }Lembre -se de que, nesses dois últimos exemplos, o LockedInindex pode acessar i sem problemas, mas usar um identificador nomeado diferente como um parâmetro da função pode facilitar a interpretação do conceito.
Uma das vantagens mais significativas de executar uma função imediatamente é que, mesmo que não seja nomeada ou anônima, a expressão da função pode ser chamada imediatamente sem usar um identificador e um fechamento pode ser usado sem a contaminação da variável atual.
Qual é o problema com a função anônima auto-executiva ("função anônima auto-executada")?
Você já viu que é mencionado várias vezes, mas ainda não é explicado com tanta clareza, sugiro mudar o termo para "expressão de função insuportada imediatamente" ou, eu, se você gosta da abreviação.
O que é a expressão de função imediatamente invocada? Ele faz uma expressão de função chamada imediatamente. É como uma expressão de função que o leva a ligar.
Eu acho que os membros da comunidade JavaScript devem ser capazes de aceitar termos, expressão de funções e funções insuficientes imediatamente em seus artigos ou declarações, porque sinto que é mais fácil entender o conceito, e o termo "função anônima auto-executiva" não é realmente precisa o suficiente.
// a seguir é uma função auto-executiva, que chama recursivamente sua própria função foo () {foo ();}; // Esta é uma função anônima auto-executiva. Como não possui identificador, ele deve usar a propriedade `argumentos.callee` para chamar de si mesmo var foo = function () {argumentos.callee ();}; // isso pode ser considerado uma função anônima auto-executiva, mas também é viável se você substituí-lo por` `` `` `» '`` `` ``' `` `` `` `'' '', que também pode ser considerado uma função anônima, mas também é viável; Função 'Assim, mesmo que não seja auto-executivo porque não se chama. Então, foi chamado imediatamente. (function () {/*code*/} ()); // Adicionando um identificador a uma expressão de função (ou seja, criar uma função nomeada) será de grande ajuda para nossa depuração. Uma vez nomeado, a função não será mais anônima. (function foo () {/ * code */} ()); // iifes também podem ser executados por si só, embora talvez não seja o padrão mais útil (function () {Argumments.callee ();} ()) (function foo () {foo ();} () // Último a ser observado: isso causará um erro e um erro de um erro em um erro em Black (). Incrível, hein? (Function foo () {foo ();} ());Esperamos que o exemplo acima lhe dê uma compreensão mais clara do termo auto-execução que é um pouco enganador porque não está executando sua própria função, embora a função tenha sido executada. Da mesma forma, não há necessidade de apontar funções anônimas, porque a expressão imediatamente de função invocada pode ser uma função nomeada ou uma função anônima.
Último: modo de módulo
Quando chamo uma expressão de função, se me lembrar do padrão do módulo pelo menos uma vez, provavelmente o ignorarei. Se você não possui o padrão do módulo no JavaScript, é muito semelhante ao meu exemplo abaixo, mas o valor de retorno usa um objeto em vez da função.
var contador = (function () {var i = 0; return {get: function () {return i;}, set: function (val) {i = val;}, increment: function () {return ++ i;}}} ()); contador.get (); // 0 contador.set (3); contador.increment (); // 4 contador.increment (); // 5 couter.i; // indefinido (`i` não é uma propriedade do objeto devolvido) i; // ReferenceError: i não é definido (ele só existe dentro do fechamento)O método do modo de módulo não é apenas bastante poderoso, mas também simples. Com muito pouco código, você pode utilizar efetivamente a nomeação relacionada a métodos e atributos. Em um objeto, a organização de todos os códigos de módulo minimiza a poluição de variáveis globais e cria o uso de variáveis.