Maison > Article > interface Web > Essai de fermeture JS
Avant de commencer l'introduction formelle, examinons une question d'entretien plus difficile sur les fermetures :
function fun(n,o) {
console.log(o)
return {
fun : function(m){
return fun(m,n);
}
};
}
var a = fun(0); (2); a.fun(3);
var b = fun(0).fun(1).fun(2).fun(3);
var c = fun(0).fun ( 1); c.fun(2); c.fun(3);
//Question : Quelles sont les sorties des trois lignes a, b et c ?
(Lien original : http://www.cnblogs.com/xxcanghai/p/4991870.html)
Cette question est difficile à comprendre pour tout le monde, surtout pour les novices qui n'ont pas de bases solides . , j'avais le vertige rien qu'en le regardant. J'ai expliqué grossièrement ce que faisait cette fonction amusante
(j'analyserai cela à la fin de l'article) : d'abord, elle a imprimé son deuxième paramètre, puis a renvoyé un objet, cet objet. a une méthode fun, puis cette méthode renvoie fun(m,n) -- le résultat de l'exécution de la fonction la plus externe ; si vous comprenez à peu près le processus de base, vous pouvez l'analyser grossièrement, mais avant de parler de fermetures ; , parlons de la chaîne de portée de
js :
Chaque morceau de code js (code global ou fonction) (faites attention ici, frappez au tableau !!!) a une portée qui lui est associée. Cette chaîne de portée
est une liste d'objets ou une liste chaînée. Ce groupe d'objets définit les variables dans la portée de ce code. Lorsque js a besoin de trouver la valeur de la variable x,
(ce processus est appelé 'Résolution de variable. (résolution variable)'), il recherchera à partir du premier objet de la chaîne s'il n'est pas trouvé dans le premier objet, il
recherchera le suivant, et ainsi de suite.
Dans le code de niveau supérieur de js, la chaîne de portée est constituée d'un objet global. Dans un corps de fonction qui ne contient pas d'imbrication, il y a deux objets sur la chaîne de portée. Le premier est l'objet où la fonction
définit les paramètres et les variables locales, et le second est l'objet global.
-Le contenu des deux paragraphes ci-dessus provient du guide faisant autorité JS, qui est le livre du rhinocéros
Lorsqu'une fonction est définie, elle préserve en fait une chaîne de domaines. Lorsque cette fonction est appelée, elle crée un nouvel objet pour stocker ses variables locales, ajoute
cet objet à la chaîne de portée enregistrée et en crée un nouveau, plus long, qui représente la portée de la chaîne d'appel de fonction. Pour les fonctions imbriquées, chaque fois que la fonction externe
est appelée, la chaîne de portée est différente et la fonction interne sera redéfinie. Chaque fois que la fonction externe est appelée, le code de la fonction interne est le même, et La chaîne de portée associée à ce code est également différente.
-Le contenu ci-dessus provient également du guide faisant autorité JS, c'est-à-dire le livre des rhinocéros
Résume généralement que chaque fonction formera une chaîne de domaine, la chaîne de domaine est différente et le contenu accessible ne l'est pas la même chose. Lors de l'accès aux variables en raison de la relation d'ordre
des objets dans la chaîne de portée, vous pouvez suivre un principe - le principe de proximité.
Après avoir parlé de périmètre, parlons de fermetures.
Bref, une chaîne de portée déroutante est la coupable des fermetures.
Prenons un exemple très simple :
var d;
function otter(){
var c = 0;
console.log(c);
d = function() { c++; >
De manière générale, chaque fois qu'une fonction js est appelée, un nouvel objet est créé pour enregistrer les variables locales, et cet objet est ajouté à la chaîne de portée
Lorsque la fonction revient, elle est supprimée de la chaîne de portée. supprimé S'il n'y a pas de fonctions imbriquées et aucune autre référence pointant vers cet objet de liaison, il sera
traité comme un garbage collection. Si des fonctions imbriquées sont définies, chaque fonction imbriquée formera sa propre chaîne de portée, et cette chaîne de portée pointe vers un objet de liaison variable
Si ces objets de fonction imbriqués sont enregistrés dans la fonction externe, ils seront également récupérés comme . les objets de liaison variable vers lesquels ils pointent. Mais
si ces fonctions imbriquées sont renvoyées sous forme de valeurs de retour ou stockées quelque part dans des attributs, il y aura une référence externe pointant vers la fonction imbriquée. Il ne sera pas traité comme un
garbage collection, et l'objet de liaison variable pointé ne sera pas traité comme un garbage collection !
Ainsi, dans le code ci-dessus, après avoir appelé outter, puisque la variable externe d fait référence à la fonction imbriquée, une fois l'exécution de outter terminée, la fonction
imbriquée pointée par d et l'objet de liaison variable vers lequel elle pointe es Ça n'a pas été recyclé, donc c n'a pas été recyclé, donc il y a une histoire future. . .
Donnons une explication en anglais de la fermeture (ce qui suit est tiré de l'explication de MDN) :
Une fermeture est la combinaison d'une fonction et de l'environnement lexical dans lequel cette
fonction a été déclarée.
Qu'est-ce que cela signifie ? La traduction directe de ce qui précède est la suivante : une fermeture est une combinaison d'une fonction et de l'environnement de portée lexicale dans lequel la fonction est déclarée.
Parlons de la question évoquée au début :
function fun(n,o) {
console.log(o)
return {
fun:function(m) {
return fun(m,n); (1).fun(2).fun (3);
Laissez-moi vous expliquer ce qui se passe lorsque cette instruction est exécutée :
fun(0):
fun(0) => n = 0,o = indéfini;
console.log(o); o = indéfini; return { fun: function(m){ return fun( m,n) } }; => Définir des fonctions imbriquées pour former une chaîne de portées, et référencée par l'attribut
de l'objet retourné fun, m = non défini, n =0, cette chaîne de portées est conservée
fun (0).fun(1):
En fait, l'appel renvoie la méthode fun de l'objet :
function(m) => m = 1;
return fun(m,n) => m=1,n=0;
Exécutez à nouveau la fonction fun :
fun(n,o) => n=1,o=0;
console.log(o) => 0
return { fun: ...return fun(m,n) } => m = undefined,n =1; Comme ci-dessus, la chaîne de portée est enregistrée
fun(0).fun(1; .fun(2):
Toujours la méthode fun de l'objet renvoyé est appelée :
function(m) => m=2
return fun(m,n) m=2,n= 1
puis appelez fun(n,o) => n=2,o=1
Ensuite, imprimer o est imprimer 1. . .
Ensuite
fun(0).fun(1).fun(2).fun(3);
Toujours la méthode fun de l'objet renvoyé est appelée :
function(m) => ; m =3
retour amusant(m,n) """"""""" La. . .
...
Le dernier b consiste à appeler la méthode fun qui renvoie l'objet Lorsque fun est exécuté, il renvoie un objet, donc b est un objet avec un attribut
dont la clé est la valeur fun. fonction. , nous appelons généralement cet attribut une méthode.
En fait, c'est le dernier point dont je veux parler. S'il est nécessaire de montrer des compétences ou des conditions, utilisez des fermetures si vous le pouvez, car tant que vous utilisez des
fermetures, cela signifie. que vous Un espace est creusé dans la mémoire que votre programme n'utilise pas nécessairement. Cependant, d'autres programmes ne peuvent pas utiliser cet espace lorsque l'ordinateur est en cours d'exécution
Cela aura sans aucun doute un impact sur les performances du programme.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!