Os fechamentos são um recurso importante no JavaScript, e sua maior função é salvar informações durante a operação da função. No JavaScript, muitos recursos dos fechamentos são derivados da cadeia de escopo durante as chamadas de função.
Escopo Cadeia de função Call Objetos e variáveis
Para cada chamada de função no JavaScript, o JavaScript criará um objeto local para armazenar as variáveis locais definidas na função; Se houver uma função aninhada dentro da função, o JavaScript definirá um objeto local aninhado no objeto local já definido. Para uma função, existem tantas camadas de definições de função aninhadas quanto existem, tantas camadas de objetos locais aninhados quanto existem. Esse objeto local é chamado de "Objeto de chamada de função" ("Objeto de chamada" no ECMAScript 3 e foi renomeado "registro do ambiente declarativo" no ECMAScript 5, mas eu pessoalmente acho que o nome no Ecmascript 3 é mais fácil de entender). As seguintes chamadas de função são usadas como exemplo:
A cópia do código é a seguinte:
função f (x) {
var a = 10;
retornar a*x;
}
console.log (f (6)); // 60
Neste exemplo simples, quando a função f () é chamada, JavaScript criará um objeto de chamada da função f () (vamos chamá -lo de f_invokeobj). Existem duas propriedades dentro do objeto f_invokeobj: a e x; Quando f () é executado, o valor A é 10 e o valor X é 6, portanto o resultado final de retorno é 60. A ilustração é a seguinte:
Quando houver ninho de funções, o JavaScript criará vários objetos de chamada de função:
A cópia do código é a seguinte:
função f (x) {
var a = 10;
retornar a*g (x);
função g (b) {
retornar b*b;
}
}
console.log (f (6)); // 360
Neste exemplo, ao chamar a função f (), o JavaScript criará um objeto de chamada da função f () (f_invokeobj), que possui dois atributos A e X, e o valor a é 10 e o valor x é 6; Ao executar f (), o JavaScript analisará e definirá a função g () na função f () e criará um objeto de chamada de g () (g_invokeobj), que possui um atributo b, e o valor B é o mesmo que o parâmetro X passado,, o resultado final de retorno é 360. A ilustração é a seguinte:
Como você pode ver, o objeto de chamada da função forma uma cadeia. Quando a função incorporada G () estiver em execução e precisa obter o valor da variável, ele começará a pesquisar no objeto de chamada de função mais recente. Se não puder ser pesquisado, pesquisando em um objeto de chamada adicional ao longo da cadeia de objetos de chamada de função, que é a chamada "cadeia de variáveis de escopo". Se a mesma variável aparecer nos dois objetos de chamada de função, a função levará o valor da variável no objeto de chamada mais próximo a ele:
A cópia do código é a seguinte:
função f (x) {
var a = 10;
retornar a*g (x);
função g (b) {
var a = 1;
retornar b*b*a;
}
}
console.log (f (6)); // 360, não 3600
No exemplo acima, a variável A possui valores diferentes no objeto de chamada (g_invokeobj) da função g () e o objeto de chamada (f_invokeobj) da função f (). Ao executar a função g (), o valor de uma função usada dentro da função g () é 1, enquanto o valor de uma função usada fora da função g () é 1. A cadeia de objetos de chamada da função neste momento é a seguinte:
O que é um fechamento?
Todas as funções no JavaScript são objetos e, ao definir funções, uma cadeia de chamadas de função correspondente será gerada. Uma definição de função corresponde a uma cadeia de funções chama objetos. Enquanto o objeto de função existir, existe o objeto de chamada de função correspondente; Depois que uma função não é mais usada, o objeto de chamada de função correspondente será coletado de lixo; e essa combinação de objeto de função e a cadeia do objeto de chamada da função é chamada de "fechamento". Nos exemplos acima da função f () e na função g (), existem dois fechamentos: o objeto de função f () e o objeto f_invokeobj formam um fechamento, e o objeto de função g () e a cadeia de objetos g_invokeobj-f_invokeobj formam o segundo fechamento. Quando a função g () é executada, como a função G () não é mais usada, o fechamento g () é coletado de lixo; Então, quando a função f () é executada, o fechamento f () também é coletado de lixo pelo mesmo motivo.
A partir da definição de fechamento, podemos tirar uma conclusão: todas as funções de JavaScript são fechamentos após a definição, porque todas as funções são objetos e todas as funções também têm suas correntes de chamadas correspondentes após a execução.
No entanto, o que faz o fechamento realmente funcionar é o caso das funções aninhadas. Como a função incorporada é definida apenas quando a função externa está em execução, o valor variável armazenado no fechamento da função incorporada (especialmente o valor variável local da função externa) é o valor durante esta execução. Desde que o objeto de função incorporado ainda exista, seu fechamento ainda existe (o valor variável no fechamento não mudará nenhum), alcançando assim o objetivo de salvar as informações do processo de execução da função. Considere o seguinte exemplo:
A cópia do código é a seguinte:
var a = "fora";
função f () {
var a = "Inside";
função g () {return a;}
retornar g;
}
var resultado = f ();
console.log (resultado ()); // dentro
Neste exemplo, quando a função f () é executada, a função g () é definida e um fechamento da função g () é criado. O fechamento g () contém a cadeia de objeto G_INVOKEOBJ-F_INVOKEOBJ; portanto, o valor da variável A durante a execução da função f () é salvo. Quando a instrução console.log () é executada, o fechamento G () ainda existe porque o objeto da função G ainda existe; Ao executar esse objeto de função G ainda existente, o JavaScript usará o fechamento G () ainda existente e obterá o valor da variável a ("dentro") dele.