Maison > interface Web > js tutoriel > le corps du texte

Explication détaillée des fermetures JavaScript_Connaissances de base

WBOY
Libérer: 2016-05-16 16:16:09
original
913 Les gens l'ont consulté

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 :


  • Liste 1

  • Liste 2

  • Liste 3

  • Liste 4

  • Liste 5



É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.

Étiquettes associées:
source:php.cn
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!