Les fermetures sont une caractéristique importante de JavaScript, et leur plus grande fonction consiste à enregistrer des informations pendant le fonctionnement de la fonction. En JavaScript, de nombreuses caractéristiques des fermetures sont dérivées de la chaîne de portée lors des appels de fonction.
Chaîne de portée des objets et variables d'appel de fonction
Pour chaque appel de fonction dans JavaScript, JavaScript créera un objet local pour stocker les variables locales définies dans la fonction; S'il existe une fonction imbriquée à l'intérieur de la fonction, JavaScript définira un objet local imbriqué sur l'objet local déjà défini. Pour une fonction, il y a autant de couches de définitions de fonctions imbriquées qu'il y en a, autant de couches d'objets locaux imbriqués qu'il y en a. Cet objet local est appelé "Fonction Call Object" ("Call Object" dans ECMAScript 3, et a été renommé "enregistrement d'environnement déclaratif" dans ECMAScript 5, mais je pense personnellement que le nom dans ECMAScript 3 est plus facile à comprendre). Les appels de fonction suivants sont utilisés comme exemple:
La copie de code est la suivante:
fonction f (x) {
var a = 10;
retourner a * x;
}
console.log (f (6)); // 60
Dans cet exemple simple, lorsque la fonction f () est appelée, JavaScript créera un objet d'appel de la fonction f () (appelons-le f_invokeobj). Il y a deux propriétés à l'intérieur de l'objet f_invokeoBj: a et x; Lorsque f () est exécuté, la valeur A est 10 et la valeur x est 6, donc le résultat de retour final est 60. L'illustration est la suivante:
Lorsqu'il y a la nidification de la fonction, JavaScript créera plusieurs objets d'appel de fonction:
La copie de code est la suivante:
fonction f (x) {
var a = 10;
retourner a * g (x);
fonction g (b) {
retour b * b;
}
}
console.log (f (6)); // 360
Dans cet exemple, lors de l'appel de la fonction f (), JavaScript créera un objet d'appel de la fonction f () (f_invokeoBj), qui a deux attributs A et X, et la valeur A est 10 et la valeur x est 6; Lors de l'exécution de F (), JavaScript analyse et définira la fonction g () dans la fonction f () et créera un objet d'appel de g () (g_invokeoBj), qui a un attribut B, et la valeur B est la même que le paramètre passant x, donc le résultat de retour final est 360. L'illustration est la suivante:
Comme vous pouvez le voir, l'objet Fonction Call forme une chaîne. Lorsque la fonction intégrée G () est en cours d'exécution et doit obtenir la valeur de la variable, elle commencera à rechercher à partir de l'objet d'appel de fonction le plus récent. S'il ne peut pas être recherché, recherchant dans un autre objet d'appel le long de la chaîne d'objets d'appel de fonction, qui est la soi-disant "chaîne de portée de variables". Si la même variable apparaît dans les deux objets d'appel de fonction, la fonction prendra la valeur de la variable dans l'objet d'appel le plus proche:
La copie de code est la suivante:
fonction f (x) {
var a = 10;
retourner a * g (x);
fonction g (b) {
var a = 1;
retour b * b * a;
}
}
console.log (f (6)); // 360, pas 3600
Dans l'exemple ci-dessus, la variable a a des valeurs différentes dans l'objet appelant (g_invokeObj) de la fonction g () et de l'objet appelant (f_invokeObj) de la fonction f (). Lors de l'exécution de la fonction g (), la valeur d'une fonction utilisée à l'intérieur de la fonction g () est 1, tandis que la valeur d'une fonction utilisée en dehors de la fonction g () est 1. La chaîne d'objets d'appel de fonction à l'heure actuelle est la suivante:
Qu'est-ce qu'une fermeture?
Toutes les fonctions dans JavaScript sont des objets, et lors de la définition des fonctions, une chaîne de fonctions correspondante appelle des objets sera généré. Une définition de fonction correspond à une chaîne de fonctions appelle des objets. Tant que l'objet de fonction existe, l'objet d'appel de fonction correspondant existe; Une fois qu'une fonction n'est plus utilisée, l'objet d'appel de fonction correspondant sera collecté aux ordures; et cette combinaison de l'objet de fonction et de l'objet de l'appel de la chaîne de fonction est appelée "fermeture". Dans les exemples ci-dessus de la fonction f () et g (), il y a deux fermetures: l'objet de fonction f () et l'objet f_invokeObj forment une fermeture, et l'objet de fonction g () et l'objet g_invokeobj-f_invokeoBJ forment la deuxième fermeture. Lorsque la fonction G () est exécutée, puisque la fonction g () n'est plus utilisée, la fermeture g () est collectée par les ordures; Ensuite, lorsque la fonction f () est exécutée, la fermeture f () est également collectée pour la même raison.
D'après la définition de la fermeture, nous pouvons tirer une conclusion: toutes les fonctions JavaScript sont des fermetures après définition car toutes les fonctions sont des objets, et toutes les fonctions ont également leurs chaînes d'objets d'appel correspondantes après exécution.
Cependant, ce qui fait que les fermetures fonctionnent vraiment, c'est le cas des fonctions imbriquées. Étant donné que la fonction intégrée n'est définie que lorsque la fonction externe est en cours d'exécution, la valeur variable stockée dans la fermeture de la fonction embarquée (en particulier la valeur variable locale de la fonction externe) est la valeur pendant cette exécution. Tant que l'objet de fonction intégré existe toujours, sa fermeture existe toujours (la valeur variable dans la fermeture ne changera aucun), atteignant ainsi le but d'enregistrer les informations du processus d'exécution de la fonction. Considérez l'exemple suivant:
La copie de code est la suivante:
var a = "à l'extérieur";
fonction f () {
var a = "inside";
fonction g () {return a;}
Retour G;
}
var result = f ();
console.log (result ()); // à l'intérieur
Dans cet exemple, lorsque la fonction f () est exécutée, la fonction g () est définie et une fermeture de la fonction g () est créée. La fermeture G () contient la chaîne d'objets g_invokeoBj-f_invokeObj, de sorte que la valeur de la variable a pendant l'exécution de la fonction f () est enregistrée. Lorsque l'instruction Console.log () est exécutée, la fermeture G () existe toujours car l'objet de fonction G existe toujours; Lors de l'exécution de cet objet de fonction G encore existant, JavaScript utilisera la fermeture g () encore existante et obtiendra la valeur de la variable a ("inside") de celui-ci.