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

js compréhension approfondie des fermetures (code ci-joint)

亚连
Libérer: 2018-05-19 14:13:56
original
1148 Les gens l'ont consulté

Cet article présente principalement la fermeture de js. La fermeture est un point relativement difficile à comprendre en js. Maintenant, je l'ai compilé et partagé avec vous. Si vous en avez besoin, vous pouvez en savoir plus.

La fermeture est un point relativement difficile à comprendre en js, surtout pour les personnes sans bases en programmation.

En fait, il n'y a que quelques éléments auxquels il faut prêter attention concernant les fermetures. Si vous les comprenez tous, il n'est pas difficile de les surmonter. Parlons de quelques principes de base des fermetures.

Le concept de fermeture

Une fermeture est une combinaison d'une fonction et de l'objet scope dans la fonction créée. (Les objets Scope seront discutés ci-dessous)

Pour le dire plus simplement, "Tant qu'une ou plusieurs fonctions sont imbriquées dans une fonction, nous pouvons les appeler une fermeture

Semblable à." ceci :

function A() {
 var i = 5;
 return function() {
  console.log('i = '+i);
 }
}

var a = A();
a(); // i = 5
Copier après la connexion

Principe de fermeture

1. est appelé par la fonction de fermeture, il ne sera pas recyclé immédiatement après l'exécution de la fonction externe.

Nous savons que quelle que soit la langue, le système d'exploitation disposera d'un mécanisme de récupération de place pour recycler l'espace alloué en excès afin de réduire la mémoire. Le cycle de vie d'une fonction commence lorsqu'elle est appelée. Lorsque l'appel de fonction est terminé, les variables locales à l'intérieur de la fonction seront recyclées par le mécanisme de recyclage.

Prenons l'exemple ci-dessus comme exemple. Lorsque notre fonction externe A est appelée, la variable locale i dans A sera recyclée par le système d'exploitation et n'existera pas. Cependant, lorsque nous utilisons une fermeture, la. le résultat sera Ce n'est plus le cas, je ne serai pas recyclé. Imaginez, si je suis recyclé, la fonction renvoyée ne s'imprimerait-elle pas de manière indéfinie ?

Pourquoi n’ai-je pas été recyclé ?

Lorsque JavaScript exécute une fonction, il crée un objet scope et enregistre les variables locales dans la fonction (les paramètres formels de la fonction sont également des variables locales), ainsi que les variables passées dans la fonction. est initialisé.

Ainsi, lorsque A est appelé, un objet scope est créé, appelons-le Aa, alors cet Aa devrait ressembler à ceci : Aa { i: 5 }; . L'objet Aa aurait dû être recyclé, mais comme la fonction renvoyée utilise l'attribut i de Aa, la fonction renvoyée enregistre une référence à Aa, donc Aa ne sera pas recyclé.

Ainsi, en comprenant l'objet scope, vous pouvez comprendre pourquoi les variables locales de la fonction ne seront pas recyclées immédiatement lorsque l'appel de fonction est terminé lors d'une fermeture.

Autre exemple :

function A(age) {
 var name = 'wind';
 var sayHello = function() {
  console.log('hello, '+name+', you are '+age+' years old!');
 };
 return sayHello;
}
var wind = A(20);
wind(); // hello, wind, you are 20 years old!
Copier après la connexion

Pouvez-vous dire quel est son objet de portée Ww ?

Ww{ age: 20; name: 'wind'; };

2. Chaque fois qu'une fonction externe est appelée, une nouvelle fermeture est générée. les uns des autres.

3. La même fermeture conservera le dernier état, et lorsqu'elle sera rappelée, elle sera basée sur la dernière fois.

L'objet scope généré à chaque fois que la fonction externe est appelée est différent. Vous pouvez y penser de cette façon. Dans l'exemple ci-dessus, l'âge du paramètre que vous transmettez est différent à chaque fois, donc l'objet généré est différent. à chaque fois.

Chaque fois qu'une fonction externe est appelée, un nouvel objet scope sera généré.

function A() {
 var num = 42;
 return function() { console.log(num++); }
}
var a = A();
a(); // 42
a(); // 43

var b = A(); // 重新调用A(),形成新闭包
b(); // 42
Copier après la connexion

Ce code nous permet de découvrir deux choses. Premièrement, lorsque nous appelons a() deux fois de suite, num changera automatiquement en fonction de. la valeur originale ajouter. Cela signifie que la même fermeture conservera le dernier état, et lorsqu'elle sera rappelée, elle sera basée sur la dernière fois. 2. Le résultat de notre b(); est 42, indiquant qu'il s'agit d'une nouvelle fermeture et qu'elle n'est pas affectée par d'autres fermetures.

Nous pouvons y penser de cette façon, tout comme nous soufflons une bulle de savon. Chaque fois que je la souffle (appelez une fonction externe), une nouvelle bulle de savon (fermeture) sera générée. Plusieurs bulles de savon peuvent exister. en même temps. Et les deux bulles de savon ne s’affecteront pas.

4. Plusieurs fonctions existant dans des fonctions externes "vivent et meurent ensemble"

Les trois fonctions suivantes sont déclarées en même temps et peuvent toutes effectuer des opérations sur les propriétés (variables locales) du objet de portée Accès et opérations.

var fun1, fun2, fun3;
function A() {
 var num = 42;
 fun1 = function() { console.log(num); }
 fun2 = function() { num++; }
 fun3 = function() { num--; } 
}

A();
fun1();  // 42
fun2(); 
fun2(); 
fun1();  // 44
fun3(); 
fun1();  //43

var old = fun1;

A(); 
fun1();  // 42
old();  // 43  上一个闭包的fun1()
Copier après la connexion

Comme les fonctions ne peuvent pas avoir plusieurs valeurs de retour, j'ai utilisé des variables globales. Encore une fois, nous pouvons voir qu'une nouvelle fermeture est créée la deuxième fois que nous appelons A().

Quand une fermeture rencontre une variable de boucle

Quand on parle de fermetures, il faut parler du moment où une fermeture rencontre une variable de boucle Voir le code suivant :

function buildArr(arr) {
  var result = [];
  for (var i = 0; i < arr.length; i++) {
    var item = &#39;item&#39; + i;
    result.push( function() {console.log(item + &#39; &#39; + arr[i])} );
  }
  return result;
}

var fnlist = buildArr([1,2,3]);
fnlist[0](); // item2 undefined
fnlist[1](); // item2 undefined
fnlist[2](); // item2 undefined
Copier après la connexion

Comment cela a-t-il pu arriver ? Les trois résultats que nous envisageons devraient être item0 1, item1 2, item2 3. Pourquoi y a-t-il trois éléments2 non définis stockés dans le tableau de résultats renvoyé ?

原来当闭包遇到循环变量时都是循环结束之后统一保存变量值,拿我们上面的例子来说,i是循环变量,当循环全部结束的时候i正好是i++之后的3,而arr[3]是没有值的,所以为undefined,有人会疑惑:为什么item的值是item2,难道不应该是item3吗?注意,在最后一次循环的时候也就是i = 2的时候,item的值为item2,当i++,i = 3循环条件不满足循环结束,此时的item的值已经定下来了,所以此时的arr[i]为arr[3],而item为item2。这样能理解吗?如果我们将代码改成这样那就说得通了:

function buildArr(arr) {
  var result = [];
  for (var i = 0; i < arr.length; i++) { 
    result.push( function() {console.log(&#39;item&#39; + i + &#39; &#39; + arr[i])} );
  }
  return result;
}

var fnlist = buildArr([1,2,3]);
fnlist[1](); // item3 undefined
Copier après la connexion

那么问题来了,如何改正呢?且看代码:

function buildArr(arr) {
  var result = [];
  for (var i = 0; i < arr.length; i++) {
    result.push( (function(n) {
      return function() {
       var item = &#39;item&#39; + n;
       console.log(item + &#39; &#39; + arr[n]);
      }
    })(i));
  }
  return result;
}

var fnlist = buildArr([1,2,3]);
fnlist[0](); // item0 1
fnlist[1](); // item1 2
fnlist[2](); // item2 3
Copier après la connexion

我们可以用一个自执行函数将i绑定,这样i的每一个状态都会被存储,答案就和我们预期的一样了。

所以以后在使用闭包的时候遇到循环变量我们要习惯性的想到用自执行函数来绑定它。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

js 闭包常见的两种情况的解析

浅谈js 闭包引起的内存泄露问题_javascript技巧

让你分分钟学会 JS 闭包

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!

É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