O fechamento é uma dificuldade na linguagem JavaScript e em seu recurso. Muitos aplicativos avançados dependem de fechamentos para implementar. Fui exposto ao conceito de fechamento há muito tempo, mas fiquei confuso e não consegui entender o que são os fechamentos de JavaScript e o que eles são úteis. Hoje eu vi um artigo sobre fechamentos de JavaScript (link original) na Internet. Foi muito bem explicado. Agora entendi completamente que os fechamentos de JavaScript são uma coisa mágica e o objetivo dos fechamentos. Vou escrever aqui para compartilhar com você. Espero que os amigos que não entendam o fechamento de JavaScript possam entender o fechamento depois de lê -los! A maior parte do conteúdo a seguir vem do texto original. Adicionei alguns comentários de código, renderizações de operação e uma pequena modificação no texto original para fácil entender!
1. O escopo das variáveis
Para entender o fechamento, você deve primeiro entender o escopo variável especial do JavaScript.
No JavaScript, o escopo das variáveis é dividido em dois tipos: variáveis globais e variáveis locais.
No JavaScript, as variáveis globais podem ser lidas diretamente dentro de uma função.
var n =; // Defina a variável global nfunction f () {alert ("Acesse a variável global n, n ="+n); // Acesse a variável global n} f (); //Resultados em execução:
Mas o contrário não é possível, as variáveis locais dentro da função não podem ser lidas fora da função.
função f () {var n =; // Defina a variável local n} alert ("Acesse a variável local n fora da função, n ="+n); // Acesse a variável local n fora da função, erro: n não está definidoResultados em execução:
Há um lugar para se notar aqui. Ao declarar variáveis internamente, você deve usar o comando var. Caso contrário, é realmente uma variável global declarada!
função f () {n =;} f (); alert ("n não é declarado com var dentro da função F1, neste momento n é uma variável global, /r /n prova: n ="+n+", o resultado de window.n == n é:"+(janela.n == n));Resultados em execução:
2. Como ler variáveis locais de fora?
Por vários motivos, às vezes precisamos obter variáveis locais dentro da função. No entanto, como mencionado anteriormente, em circunstâncias normais, isso não pode ser feito e só pode ser alcançado por meio de soluções alternativas.
Isso é para definir outra função dentro da função.
função f () {var n =; // variável local n interna fu função // define uma função f função f () {// função f interna f, alert (n); //}}No código acima, a função F2 está incluída na função interna F1 e todas as variáveis locais dentro de F1 são visíveis para F2. Mas o contrário não é possível. As variáveis locais dentro de F2 são invisíveis para F1. Esta é a estrutura do "escopo da cadeia" exclusivo da linguagem JavaScript. Os objetos infantis procurarão o nível para cima por nível para todas as variáveis de objetos pais. Portanto, todas as variáveis do objeto pai são visíveis para o objeto filho, caso contrário, não é verdadeiro. Como F2 pode ler variáveis locais em F1, desde que F2 seja usado como valor de retorno, não podemos ler suas variáveis internas fora da F1? Algumas pessoas podem ter dúvidas. F2 é uma função, como ela pode ser retornada como o valor de retorno da função F1? Na verdade, está tudo bem. O nome da função em JavaScript é uma variável, portanto a função também pode ser usada como uma variável normal. Ou seja, não apenas uma função pode ser passada para outra função como parâmetros de passagem, mas uma função também pode ser retornada como o valor de retorno de outra função.
função f () {var n =; // Função de variável local N // Função declarada dentro da função f () {alert (n); } retornar f; // use a função f como o valor de retorno da função f} var resultado = f (); // o valor de retorno após f é chamado é uma função f, e o resultado é o resultado da função f (); // 999, ligue para F2 FunçãoResultados em execução:
3. O conceito de fechamento
A função F2 na seção anterior do código é o fechamento. A definição de "fechamento" em vários documentos profissionais é muito abstrata. Por exemplo, há uma definição de fechamento: "Um fechamento de JavaScript é uma variável que obtém da função ou escopo de nível anterior em outro escopo, e essas variáveis não serão destruídas à medida que a execução da função de nível anterior é concluída". É difícil para mim entender essa definição de fechamento. Meu entendimento é que um fechamento é uma função que pode ler variáveis dentro de outras funções. Como no idioma JavaScript, apenas as subfunções internas podem ler variáveis locais, os fechamentos podem ser simplesmente entendidos como "funções definidas dentro de uma função". Assim, em essência, um fechamento é uma ponte que conecta o interior e o exterior da função.
4. O objetivo do fechamento
Os fechamentos podem ser usados em muitos lugares. Ele tem dois maiores usos, um é que as variáveis dentro da função podem ser lidas como mencionadas acima, e a outra é que os valores dessas variáveis são sempre mantidos na memória.
Como entender esta frase? Por favor, veja o código abaixo.
Função f () {var n =; // nadd é uma variável global que não é declarada usando var. Essa variável agora aponta para uma função anônima declarada dentro da função f nadd = function () {n+=} função f () {alert (n); } retornar f; } var resultado = f (); // resultado é o resultado da função f (); // a primeira chamada para a função de resultado nadd (); // nadd representa uma função anônima declarada dentro da função f, nadd () é o resultado da função anônima (); // a segunda chamada para a função de resultado 1Resultados em execução:
Neste código, o resultado é na verdade a função F2 de fechamento. Ele é executado duas vezes no total, o primeiro valor é 999 e o segundo valor é 1000. Isso prova que a variável local n na função F1 foi mantida na memória e não é automaticamente limpa após a chamada F1.
Por que isso está acontecendo? O motivo é que a F1 é a função pai de F2 e F2 é atribuída a uma variável global, o que faz com que F2 esteja sempre na memória, e a existência de F2 depende de F1. Portanto, a F1 está sempre na memória e não será reciclada pelo mecanismo de coleta de lixo após o término da chamada.
Outro ponto notável neste código é que a linha "nadd = function () {n+= 1}" é usada pela primeira vez antes do NADD, então o NADD é uma variável global, não uma variável local. Em segundo lugar, o valor do NADD é uma função anônima, e essa função anônima em si também é um fechamento, portanto, o NADD é equivalente a um setter, que pode operar em variáveis locais dentro da função fora da função.
5. Notas sobre o uso de fechamentos
1) Como o fechamento fará com que todas as variáveis da função sejam armazenadas na memória e o consumo de memória é muito grande, os fechamentos não podem ser abusados, caso contrário, causará problemas de desempenho da página da Web e poderá levar ao vazamento de memória no IE. A solução é excluir todas as variáveis locais que não são usadas antes de sair da função.
2) O fechamento alterará o valor da variável dentro da função pai fora da função pai. Portanto, se você usar a função pai como objeto, use o fechamento como método público e use a variável interna como sua propriedade privada, tome cuidado para não alterar o valor da variável interna da função pai à vontade.
6. Perguntas de pensamento
Se você pode entender os resultados em execução das duas partes seguintes de código, você deve entender o mecanismo de execução do fechamento.
Snippet de código 1:
var name = "The Window"; var object = {nome: "meu objeto", getNameFunc: function () {return function () {return this.name; }; }}; alert (object.getNamefunc () () ());Resultados em execução:
Snippet de código dois:
var name = "The Window"; var object = {nome: "meu objeto", getNameFunc: function () {var that = this; return function () {return that.name; }; }}; alert (object.getNamefunc () () ());Resultados em execução:
Os seguintes comentários são adicionados ao código para analisar os resultados em execução dos dois trechos de código acima:
Snippet de código 1:
A análise é a seguinte:
/*Em JavaScript, os objetos globais JavaScript, funções globais e variáveis globais que declaramos se tornarão automaticamente membros do objeto da janela. Variáveis globais são propriedades de objetos de janela. As funções globais são métodos de objetos de janela. */var name = "The Window"; // Declare um nome de variável global e, neste momento, o nome da variável global se tornará automaticamente um atributo do objeto da janela // prova: alert ("window.name:"+window.name); // você pode acessar o nome no formulário de janela. Tempo O objeto Global Variable Objeto se tornará automaticamente um atributo do objeto de janela var objeto = {nome: "Meu objeto", // Nome do atributo do objeto GetNameFunc: function () {// GetNameFunc função do objeto Objeto // O valor de retorno deste método GetNameFunc do objeto é uma função da função anônima, // (// AT ESTE para qual objeto. // Prove que isso na função anônima representa um objeto de janela em vez de um objectalert ("este resultado do objeto == é:"+(this == object)); alerta ("Este resultado da janela é:"+(this == Window)); Retorne este.name; // Como isso representa um objeto de janela, então isso. Nome naturalmente o nome do objeto da janela "The Window"}; }}; // prova: o objeto global é um atributo do objeto de janela alerta ("window.object:"+window.object); alert ("window.object.name:"+window.object.name);*Após chamar o método getNamefunc, um método anonymous é retornado. Neste momento, o retfn representa um método anônimo. Agora é equivalente a fornecer ao método anônimo um nome retfn. No momento, a função retfn se torna automaticamente uma função do objeto da janela*/var retfn = object.getNamefunc (); alert (retfn ()); // chamando o método anônimo retornado, então quem está chamando esse método anônimo? É um objeto de janela // prova: a função retfn é uma função do alerta do objeto da janela ("window.retfn ():"+window.retfn ()); // você pode chamar o método retfn na forma de window.retfn () (nome do objeto. Nome do método), então ele prova que a função retfn é uma função da função da função da janelaSnippet de código dois:
A análise é a seguinte:
var name = "The Window"; // Nome da variável global // Global Object ObjectVar Object = {Nome: "My Object", GetNameFunc: function () {/*Qual objeto isso representa isso neste momento? Isso representa o objeto do objeto. Qual objeto chama a função onde está localizado? Refere -se a qual objeto foi executado isso = isso, e isso também representa o objeto objeto*/var que = this; // Essa é uma variável local declarada no GetNameFunc function // prova que isso na função getNamefunc representa o objeto do objeto em vez de windowalert ("Este resultado do objeto é:"+(this == Object); alert ("Este resultado da janela é:"+(this == Window)); // Prove que representa o alerta do objeto de objeto ("que == resultado do objeto é:"+(that == Object)); Return function () {/*Essa é uma variável local declarada na função getNamefunc. Em circunstâncias normais, após a conclusão da chamada da função GetNameFunc, a variável local que será reciclada pelo GC do JavaScript, liberando o espaço de memória ocupado pela variável local que, mas agora isso pode ser usado normalmente e não foi reciclado. O motivo é que GetNameFunc é a função pai da função anônima. Depois que a função GetNameFunc for chamada, a função anônima será retornada e atribuída a um retirável variável global, o que faz com que a função anônima esteja sempre na memória, e a existência da função anônima depende da função getNamefunc. Portanto, a função GetNameFunc está sempre na memória e não será reciclada pelo mecanismo de coleta de lixo após o término da chamada. Como a função GetNameFunc está sempre na memória, a variável local declarada dentro da função GetNameFunc sempre existirá na memória. Como existe, é claro que pode continuar sendo usado. */return th That.name; // que representa o objeto Objeto, para que.Name naturalmente acesse o nome do objeto "meu objeto"}; }}; var retfn = object.getNamefunc (); // Depois de chamar o método getNameFunc, um método anônimo é retornado. No momento, o retfn representa um método anônimo, que agora é equivalente a fornecer ao método anônimo um nome é alerta retfn (retfn ());Finalmente, também anexei um exemplo que escrevi quando aprendi o fechamento de javascript antes:
<script type = "text/javascript"> function a () {var i =; // declara a variável local i interna função a/declara a subfunção bfunção b () {alert ("i ="+(++ i); // Acesse a variável local I declarou a função interna a} retorno b; retorno); a função b. b. A variável i é usada. Após a execução de C (), uma janela aparecerá para exibir o valor de I (a primeira vez) e esse código realmente cria um fechamento, porque a variável C fora da função A se refere à função B Função interna a. Ou seja: quando a função interna B da função A é referenciada por uma função externa variável A, o chamado fechamento de "fechamento" é criado. Depois que A foi executado e devolvido, o fechamento faz com que o mecanismo de coleta de lixo JavaScript GC não recicle os recursos ocupados por A, porque a execução da função interna B de A precisa confiar na variável em A */A (); // Definitivamente, haverá espaço na memória. Depois que A () for executado, o GC reciclará o espaço de memória alocado para i var c = a (); // esse uso, GC não tratará I como lixo e c (); // equivalente à chamada b (), o resultado é: i = c (); // o resultado é: i = c (); // o resultado é: i = c ();Resultados em execução:
O conteúdo acima é a explicação detalhada do código de fechamento JavaScript (fechamento) dos pontos de conhecimento JavaScript resumidos (16) introduzidos pelo editor. Espero que seja útil para todos!