Maison  >  Article  >  interface Web  >  Explication détaillée de la façon d'écrire et de fonctionner des fermetures en JavaScript

Explication détaillée de la façon d'écrire et de fonctionner des fermetures en JavaScript

高洛峰
高洛峰original
2017-01-20 13:12:421261parcourir

1. Qu'est-ce qu'une fermeture

Une fermeture est une fonction qui a accès à une variable dans la portée d'une autre fonction.
En termes simples, Javascript permet l'utilisation de fonctions internes --- c'est-à-dire que les définitions de fonction et les expressions de fonction sont situées dans le corps de fonction d'une autre fonction. De plus, ces fonctions internes ont accès à toutes les variables locales, paramètres et autres fonctions internes déclarées dans la fonction externe dans laquelle elles existent. Une fermeture est formée lorsqu'une de ces fonctions internes est appelée en dehors de la fonction externe qui les contient.

2. Portée des variables

Pour comprendre les fermetures, vous devez d'abord comprendre la portée des variables.
La portée des variables n'est rien de plus que deux types : les variables globales et les variables locales.

La particularité du langage Javascript est que les variables globales peuvent être lues directement à l'intérieur de la fonction.

La fonction interne peut accéder aux variables de la fonction externe car la chaîne de portée de la fonction interne inclut la portée de la fonction externe

peut également être comprise comme : la portée de l'interne ; function Rayonnant vers la portée de la fonction externe;

var n=999;
function f1(){
 alert(n);
}
f1(); // 999

En revanche, les variables locales à l'intérieur de la fonction ne peuvent pas être lues en dehors de la fonction.

function f1(){
 var n=999;
}
alert(n); // error

Il y a une chose à noter ici Lorsque vous déclarez des variables dans une fonction, vous devez utiliser la commande var. Si vous ne l'utilisez pas, vous déclarez en fait une variable globale !

function f1(){
  n=999;
}
f1();
alert(n); // 999

3. Plusieurs façons d'écrire et d'utiliser les fermetures

3.1 Ajouter quelques attributs à la fonction

function Circle(r) {
this.r = r;
}
Circle.PI = 3.14159;
Circle.prototype.area = function() {
return Circle.PI * this.r * this.r;
}
var c = new Circle(1.0);
alert(c.area()); //3.14159

3.2. Déclarer une variable et attribuer une fonction comme valeur à la variable

var Circle = function() {
var obj = new Object();
obj.PI = 3.14159;
 
obj.area = function( r ) {
return this.PI * r * r;
}
return obj;
}
var c = new Circle();
alert( c.area( 1.0 ) ); //3.14159

3.3. Cette méthode est utilisée plus souvent et est la plus pratique. var obj = {} consiste à déclarer un objet vide

var Circle={
"PI":3.14159,
"area":function(r){
return this.PI * r * r;
}
};
alert( Circle.area(1.0) );//3.14159

4. La fonction principale de la fermeture

La fermeture peut être utilisée dans De nombreux endroits. Ses plus grandes utilisations sont au nombre de deux : l'une consiste à lire les variables à l'intérieur de la fonction comme mentionné précédemment, et l'autre est de conserver les valeurs de ces variables en mémoire.

4.1. Comment lire les variables locales de l'extérieur ?

Pour diverses raisons, nous avons parfois besoin d'obtenir des variables locales au sein d'une fonction. Cependant, comme mentionné précédemment, cela n’est pas possible dans des circonstances normales et ne peut être réalisé que grâce à des solutions de contournement.

C'est-à-dire définir une fonction à l'intérieur de la fonction.

function f1(){
  var n=999;
  function f2(){
    alert(n); // 999
  }
}

Dans le code ci-dessus, la fonction f2 est incluse dans la fonction f1 À l'heure actuelle, toutes les variables locales à l'intérieur de f1 sont pour f2 visible. Mais l’inverse ne fonctionne pas. Les variables locales à l’intérieur de f2 sont invisibles pour f1. Il s'agit de la structure "chain scope" propre au langage Javascript. L'objet enfant recherchera les variables de tous les objets parents niveau par niveau. Par conséquent, toutes les variables de l’objet parent sont visibles par l’objet enfant, mais l’inverse n’est pas vrai.

Puisque f2 peut lire les variables locales dans f1, alors tant que f2 est utilisé comme valeur de retour, ne pouvons-nous pas lire ses variables internes en dehors de f1 ?

function f1(){
  var n=999;
  function f2(){
    alert(n);
  }
  return f2;
}
var result=f1();
result(); // 999

4.2. Comment garder la valeur d'une variable en mémoire ?

function f1(){
  var n=999;
  nAdd=function(){n+=1}
  function f2(){
    alert(n);
  }
  return f2;
}
var result=f1();
result(); // 999
nAdd();
result(); // 1000

Dans ce code, le résultat est en fait la fonction de fermeture f2. Il a été exécuté deux fois, la première fois, la valeur était de 999, la deuxième fois, la valeur était de 1 000. Cela prouve que la variable locale n dans la fonction f1 est toujours stockée en mémoire et n'est pas automatiquement effacée après l'appel de f1.

Pourquoi cela se produit-il ? La raison en est que f1 est la fonction parent de f2 et que f2 est affecté à une variable globale, ce qui fait que f2 est toujours en mémoire, et l'existence de f2 dépend de f1, donc f1 est toujours en mémoire et ne sera pas supprimé. une fois l'appel terminé, recyclé par le mécanisme de récupération de place (garbage collection).

Une autre chose à noter dans ce code est la ligne "nAdd=function(){n =1}". Tout d'abord, le mot-clé var n'est pas utilisé avant nAdd, donc nAdd est plutôt une variable globale. que les variables locales. Deuxièmement, la valeur de nAdd est une fonction anonyme, et la fonction anonyme elle-même est également une fermeture, donc nAdd est équivalent à un setter, qui peut opérer sur des variables locales à l'intérieur de la fonction en dehors de la fonction.

5. La fermeture et cet objet

L'utilisation de cet objet dans une fermeture peut poser quelques problèmes. Parce que l'exécution de fonctions anonymes est globale, cet objet pointe généralement vers window. Le code est le suivant :

var name = "The window";
var object = {
name:"My object",
getNameFun:function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFun(){}); //"The window"(在非严格模式下)

Enregistrez cet objet en externe. scope Dans une variable à laquelle la fermeture peut accéder, vous pouvez laisser la fermeture accéder à l'objet. Le code est le suivant :

var name = "The window";
var object = {
name:"My object",
getNameFun:function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFun(){}); //“My object”

6. Fermetures et fuites de mémoire

Plus précisément, si un élément HTML est stocké dans la portée de la fermeture, alors Ceci signifie que l'élément ne peut pas être détruit. Comme suit :

function assignHandler(){
var element = document.getElementById("someElement");
element.onclick = function(){
alert(element.id);
}
}

Le code ci-dessus crée une fermeture en tant que gestionnaire d'événement d'élément, et cette fermeture crée une référence circulaire. Puisque la fonction anonyme enregistre une référence à l'objet actif de assignHandler(), le nombre de références à l'élément ne peut pas être réduit. Tant que la fonction anonyme existe, le numéro de référence de l'élément est au moins 1, donc la mémoire occupée par celle-ci ne sera pas recyclée.

Résoudre le problème de non-recyclabilité interne en réécrivant le code :

function assignHandler(){
var element = document.getElementById("someElement");
var id = element.id;
element.onclick = function(){
alert(id);
}
element = null;
}

Le code ci-dessus implémente la fermeture sans référencer directement l'élément, et une référence sera toujours enregistrée dans l'objet actif contenant la fonction. Il est donc nécessaire de mettre la variable element à null pour que la mémoire qu'elle occupe puisse être recyclée normalement.

7. Points à noter lors de l'utilisation des fermetures

1) Étant donné que les fermetures entraîneront le stockage des variables de la fonction en mémoire, ce qui consomme beaucoup de mémoire, les fermetures ne peuvent pas être abusées, sinon Cela entraînera des problèmes de performances sur les pages Web et pourra provoquer des fuites de mémoire dans IE. La solution consiste à supprimer toutes les variables locales inutilisées avant de quitter la fonction.

2) La fermeture modifiera la valeur de la variable à l'intérieur de la fonction parent en dehors de la fonction parent. Par conséquent, si vous utilisez la fonction parent comme objet, la fermeture comme méthode publique et les variables internes comme valeur privée, vous devez faire attention à ne pas modifier librement la valeur de la variable à l'intérieur de la fonction parent.

Ce qui précède est une explication détaillée de l'écriture et de la fonction des fermetures en JavaScript introduites par l'éditeur. J'espère que cela vous sera utile. Si vous avez des questions, veuillez me laisser un message et l'éditeur le fera. vous répondrons à temps. Je voudrais également vous remercier tous pour votre soutien au site Web PHP chinois !

Pour des explications plus détaillées sur l'écriture et les fonctions des fermetures en JavaScript, faites attention au site PHP chinois !

Déclaration:
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