Maison interface Web js tutoriel Explication détaillée des fermetures JavaScript_Connaissances de base

Explication détaillée des fermetures JavaScript_Connaissances de base

May 16, 2016 pm 04:16 PM
javascript 闭包

Dans le dernier article, nous avons donné un aperçu de la pré-interprétation. Avant d'écrire cet article de blog, nous avions prévu d'écrire quelques cas classiques. Considérant que ces cas sont relativement complets, nous avons rédigé cet article étape par étape, donc. que nous pouvons Il est également plus facile de commencer à apprendre et à approfondir JavaScript.

Préface

Un collègue est allé passer un entretien et l'intervieweur a posé une question : pouvez-vous rédiger une conclusion et me laisser y jeter un œil ? Mon collègue a donc rapidement écrit le code suivant :

Copier le code Le code est le suivant :

fonction fn(){
alert('Bonjour JavaScript Closure !!!'); // Bon sang, le texte E n'est pas bon, j'ai donc dû trouver un traducteur pour écrire les mots de fermeture
>
fn();

Puis l'intervieweur a secoué la tête et a dit : « Comment cela peut-il être appelé une clôture ? » En fin de compte, les deux n'ont pas pu se disputer, et le collègue est parti de manière décisive. Que diable fait l'intervieweur ? (Cette histoire est purement fictive, toute similitude est purement fortuite)

La fermeture est peut-être une technologie « haut de gamme et difficile à apprendre » aux yeux de beaucoup de gens. Peut-être qu'aux yeux de beaucoup de gens, c'est la seule qui compte comme fermeture :

Exemple 1 :

Copier le code Le code est le suivant :

fonction fn() {
Fonction de retour () {
alert('Exemple 1');
>
>
fn()();

Exemple 1 PS : Cela n’a pas l’air très avancé, on dirait que cette personne n’est pas très bonne !

Exemple 2 :

Copier le code Le code est le suivant :

;(fonction () {
alert('Exemple 2');
})();

Exemple 2 PS : Celui-ci a l'air plus avancé que le précédent, et un point-virgule est ajouté avant la première parenthèse. Eh bien, laissons cette question ici pour l'instant et nous en reparlerons plus tard.

Exemple 3 :

Copier le code Le code est le suivant :

~fonction fn() {
alert('Exemple 3')
}();

Exemple 3 PS : C’est le plus avancé, c’est incroyable je ne lis pas beaucoup, alors ne me mentez pas !

Je ne lis pas beaucoup, donc je ne peux écrire que ces trois types de « clôtures ». Je pense que les autres blogueurs peuvent écrire des « clôtures » plus nombreuses et de meilleure qualité ; Je connais déjà le mécanisme de fonctionnement de la fonction. Ce doit être la portée. Je ne veux vraiment pas ajouter cette portée au titre. Cela semble toujours presque dénué de sens. Vieille habitude, codez d'abord :

Copier le code Le code est le suivant :

var n = 10;
fonction fn(){
alerte(n);
var n = 9;
alerte(n);
>
fn();

Pour faire simple, faisons un dessin (l'auteur n'utilisera que le logiciel de dessin fourni avec Windows. S'il en existe un meilleur, merci de le recommander) pour l'analyser :

Analyse 1

Sur l'image, nous voyons deux portées, l'une est la portée de la fenêtre (portée de niveau supérieur) et l'autre est une portée privée formée lorsque fn est appelé ; alors qu'est-ce qu'une portée, la portée est en fait un environnement d'exécution de code. Par exemple, l'environnement d'apprentissage d'un élève est l'école, ce qui équivaut à sa portée. Si cet élève est très méchant et va souvent dans un cybercafé pour jouer à des jeux le soir, cela équivaut à former un environnement privé, et cette portée est la. Cybercafé. D'accord! Ce marron ressemble tellement au masturbateur lui-même que je n'ai pas pu m'empêcher de soupirer : "Si tu ne travailles pas dur quand tu es jeune, tu te feras botter quand tu seras grand." Revenons au sujet, en fait, la définition de la fonction fn est une description pointant vers un morceau de code (case rouge dans l'image). Lorsque fn est appelé (case verte dans l'image), une portée sera bien sûr formée. , dans cette portée Le code sera également pré-interprété avant l'exécution. Je ne vous dirai pas que cette portée sera détruite après son exécution. Appeler à nouveau ce fn formera également une nouvelle portée, puis une pré-interprétation avant l'exécution, puis le code est exécuté détruit après l'exécution finale.

Comprendre les fermetures

Nous savons que lorsqu'une fonction est appelée, elle formera une portée privée (environnement d'exécution), et cette portée privée est une fermeture. Avec le recul, la fermeture est-elle toujours le légendaire « grand et difficile à maîtriser » ? Revenons au premier récit d'interview et aux trois exemples que j'ai écrits. Ce sont en fait des fermetures. Pour être précis, ces trois exemples sont tous des formes courantes de fermetures.

Scénarios d'application

Maintenant, il existe une telle exigence : il y a une balise ul dans la page HTML, et il y a 5 balises li sous la ul. Il est nécessaire de cliquer sur n'importe quel li, et la position d'index (l'index commence à partir de 0). le li cliqué apparaîtra et la structure HTML comme suit :

Copier le code Le code est le suivant :

<ul id="ul">
<li>Liste 1</li>
<li>Liste 2</li>
<li>Liste 3</li>
<li>Liste 4</li>
<li>Liste 5</li>
</ul>

Étant malin, j'ai rapidement écrit le code suivant :

Copier le code Le code est le suivant :

var lis = document.getElementById('ul').getElementsByTagName('li');
pour (var i = 0, len = lis.length; i < len; i ) {
lis[i].onclick = fonction () {
alerte(i);
};
>

Test final pour voir si cette exigence est parfaitement réalisée :

J'ai découvert que peu importe le nombre de fois que je clique, ce résultat finira par apparaître, et le résultat attendu est : cliquez sur la liste 1 pour afficher 0, cliquez sur la liste 2 pour afficher 1, cliquez sur la liste 3 pour pop up 2... Je veux juste utiliser cette photo en ce moment Pour décrire mon humeur actuelle :

(À quoi cela ressemble lorsque le prototype ne fonctionne pas comme prévu lors de la démonstration)

Comment cela peut-il être fait ? Pourquoi 5 apparaît-il toujours ? C'est théoriquement correct ! Faisons un dessin pour l'analyser :

En fait, le onclick que nous venons de donner à chaque li est en fait une chaîne de description enregistrée d'une fonction. Le contenu de cette chaîne est le contenu de la case rouge dans l'image ci-dessus. J'ai une photo avec la vérité :

Entrez : lis[4].onclick dans la console Chrome, la valeur est la description de la fonction. Lorsque nous cliquons sur la cinquième liste, cela équivaut en fait à lis[4].onclick(), appelant cette description de fonction. Nous savons que la fonction formera une portée privée lorsqu'elle sera appelée et exécutée dans cette portée privée. est également pré-interprété en premier, puis le code est exécuté à ce moment-là, i est trouvé Il n'y a pas de i dans la portée privée actuelle, puis i est trouvé dans la portée de la fenêtre, donc 5 apparaît à chaque fois que vous cliquez. .

De toute évidence, le code ci-dessus ne peut pas répondre à cette exigence. Il est incorrect pour nous d'écrire le code comme celui-ci. Réfléchissons à la cause du problème ? En fait, la raison est qu'à chaque fois que vous cliquez, vous lisez le i sous la fenêtre. A ce moment, la valeur de i est déjà 5, vous avez donc le code suivant :

.

Méthode 1 :

Copier le code Le code est le suivant :

var lis = document.getElementById('ul').getElementsByTagName('li');
fonction fn(i) {
Fonction de retour () {
alerte(i);
>
>
pour (var i = 0, len = lis.length; i < len; i ) {
lis[i].onclick = fn(i);
>

Méthode 2 :

Copier le code Le code est le suivant :

var lis = document.getElementById('ul').getElementsByTagName('li');

pour (var i = 0, len = lis.length; i < len; i ) {
;(fonction (i) {
          lis[i].onclick = function () {
alerte(i);
        };
})(i);
>

Méthode 3 :

Copier le code Le code est le suivant :

var lis = document.getElementById('ul').getElementsByTagName('li');

pour (var i = 0, len = lis.length; i < len; i ) {
lis[i].onclick = fonction fn(i) {
         fonction de retour () {
alerte(i);
>
}(je);
>

J'ai écrit trois méthodes d'un seul coup. L'idée est la même, c'est à dire de stocker la variable i dans une variable privée. Ici, je ne parlerai que de la deuxième méthode. Bien sûr, si vous en comprenez une, vous. comprendra le reste. Comme d'habitude, on dessine des images à analyser étape par étape :

J'ai décrit l'intégralité de l'exécution du code en détail. Il convient de noter que l'attribut onclick de chaque li doit occuper la portée (function(i){…})(i) Lorsque cette fonction est exécutée, elle ne le sera pas. être détruit car il est occupé par un li externe (ce li est sous la portée de la fenêtre), donc cette portée ne sera pas détruite. Lorsqu'un li est cliqué, function(){ alert(i); } sera exécuté et une portée sera formée. Cette portée n'a pas de i, et elle ira à (function(){ ... })(. i) scope. Trouvez i, et enfin trouvez i dans le paramètre formel. La valeur de ce paramètre formel i est transmise lors de la boucle for ; cet exemple utilise intelligemment des fermetures pour stocker les valeurs, ce qui résout parfaitement le problème.

PS : je viens de mentionner pourquoi un point-virgule est ajouté devant (function(i){ … })(i). La raison est d'éviter que l'instruction précédente oublie d'ajouter un point-virgule, ce qui provoquerait des erreurs JavaScript lors du processus. analyse. C'est tout. Bien sûr, l'un des scénarios d'application ci-dessus est le principe d'implémentation des onglets. Il peut y avoir d'autres méthodes d'implémentation, telles que les méthodes d'attributs personnalisées et la recherche d'index via les relations entre les nœuds DOM. L'objectif principal de l'utilisation de cette méthode est d'approfondir la compréhension des fermetures. .

Résumé

Les fermetures ne sont pas légendaires et difficiles à maîtriser. L'essentiel est de comprendre la définition et l'appel d'une fonction. Lorsqu'une fonction est appelée, une nouvelle portée privée est formée. cette portée ne sera pas détruite. Lu Zhu a très peu lu, j'aimerais donc demander à mes collègues blogueurs de me corriger si je me trompe. Je voudrais également remercier tout le monde pour leur soutien aux articles de Lu Zhu.

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Article chaud

Combien de temps faut-il pour battre Split Fiction?
3 Il y a quelques semaines By DDD
Repo: Comment relancer ses coéquipiers
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: Comment obtenir des graines géantes
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Musée à deux points: toutes les expositions et où les trouver
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌

Article chaud

Combien de temps faut-il pour battre Split Fiction?
3 Il y a quelques semaines By DDD
Repo: Comment relancer ses coéquipiers
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: Comment obtenir des graines géantes
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Musée à deux points: toutes les expositions et où les trouver
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌

Tags d'article chaud

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Quelle est la signification de la fermeture dans l'expression lambda C++ ? Quelle est la signification de la fermeture dans l'expression lambda C++ ? Apr 17, 2024 pm 06:15 PM

Quelle est la signification de la fermeture dans l'expression lambda C++ ?

Comment implémenter la fermeture dans une expression C++ Lambda ? Comment implémenter la fermeture dans une expression C++ Lambda ? Jun 01, 2024 pm 05:50 PM

Comment implémenter la fermeture dans une expression C++ Lambda ?

Quels sont les avantages et les inconvénients des fermetures dans les fonctions C++ ? Quels sont les avantages et les inconvénients des fermetures dans les fonctions C++ ? Apr 25, 2024 pm 01:33 PM

Quels sont les avantages et les inconvénients des fermetures dans les fonctions C++ ?

Résoudre le problème de fuite de mémoire causé par les fermetures Résoudre le problème de fuite de mémoire causé par les fermetures Feb 18, 2024 pm 03:20 PM

Résoudre le problème de fuite de mémoire causé par les fermetures

L'impact des pointeurs de fonction et des fermetures sur les performances de Golang L'impact des pointeurs de fonction et des fermetures sur les performances de Golang Apr 15, 2024 am 10:36 AM

L'impact des pointeurs de fonction et des fermetures sur les performances de Golang

Comment les fermetures sont-elles implémentées en Java ? Comment les fermetures sont-elles implémentées en Java ? May 03, 2024 pm 12:48 PM

Comment les fermetures sont-elles implémentées en Java ?

Appels enchaînés et fermetures de fonctions PHP Appels enchaînés et fermetures de fonctions PHP Apr 13, 2024 am 11:18 AM

Appels enchaînés et fermetures de fonctions PHP

Résumé des avantages et des inconvénients des fonctions et fermetures anonymes de Golang Résumé des avantages et des inconvénients des fonctions et fermetures anonymes de Golang May 05, 2024 am 09:54 AM

Résumé des avantages et des inconvénients des fonctions et fermetures anonymes de Golang

See all articles