Compréhension des fermetures en JavaScript

Table des matières

1. Présentez :

2. Qu'est-ce qu'une fermeture ?

3. Conditions de génération de fermeture :

4. Fermetures courantes

5. Le rôle de la clôture

6. Cycle de vie de la fermeture

7. Demande de clôture

8. Inconvénients et solutions des fermetures

Supplément : débordement de mémoire et fuite de mémoire


1. Présentez :

Nous avons maintenant une exigence : il y a trois boutons, et lorsqu'un bouton est cliqué, il affiche "le nième bouton est cliqué".

Code:

    var btns = document.querySelectorAll('button')
    //遍历加监听
    for (var i = 0; i < btns.length; i++) {
      btns[i].onclick = function () {
        console.log(`第${i + 1}个按钮`)
      }
    }

De cette manière, quel que soit le bouton cliqué, le "4ème bouton" apparaîtra.

En effet, l'événement de clic sur le bouton n'est appelé que lorsqu'il se déclenche. Lorsque le code console.log(`le bouton ${i + 1}`) est exécuté et que l'événement click est exécuté, la boucle for a été exécutée. L'ensemble du processus produit finalement un seul i, à ce moment la valeur de i est devenue 3, quel que soit le bouton cliqué, i=3, donc sortie 3+1=4, qui est le "4ème bouton". En d'autres termes, pendant les 3 premiers cycles, l'événement click n'a pas été exécuté.

Nous pouvons modifier le code :

Nous enregistrons i, correspondons à i de chaque btn et connaissons la valeur d'index i de chaque bouton btn. De cette façon, cliquer sur le bouton affichera la valeur correspondante.

    var btns = document.querySelectorAll('button')
    for (var i = 0; i < btns.length; i++) {
       //将btn所对应的索引值保存到btn上
      btns[i].index = i
      btns[i].onclick = function () {
        console.log(`第${this.index + 1}个按钮`)
      }
    }

À ce moment, la sortie peut être normale.

Bien sûr, il existe un autre moyen de placer l'instruction de sortie dans une fonction anonyme à invocation automatique.

    var btns = document.querySelectorAll('button')
    for (var i = 0; i < btns.length; i++) {
      (function (i) {
        btns[i].onclick = function () {
          console.log(`第${i + 1}个按钮`)
        }
      })(i)
    }

À ce moment, il peut également sortir normalement.

 Cela utilise des fermetures.

2. Qu'est-ce qu'une fermeture ?

Une fermeture se produit lorsqu'une fonction interne imbriquée (enfant) fait référence à une variable (fonction) d'une fonction externe imbriquée (parent).

  function fn1() {
      var a = 2
      var b = 'abc'
      function fn2() {
        console.log(a)
      }
      fn2()
  }
  fn1()

Autrement dit, la fonction fn2 imbriquée interne fait référence à la variable a dans la fonction fn1 externe, et fn2 génère une fermeture à ce moment.

Alors, que sont exactement les fermetures ?

①Compréhension 1 : La fermeture est une fonction interne imbriquée, voici la fonction fn2.

②Compréhension 2 : L'objet contenant la variable référencée (fonction), c'est-à-dire la variable a référencée dans la fonction interne fn2.

Remarque : Des fermetures existent à l'intérieur des fonctions internes imbriquées.

3. Conditions de génération de fermeture :

① Imbrication de fonctions

②La fonction interne fait référence aux données de la fonction externe (variable/fonction)

③ Exécuter et appeler des fonctions externes

4. Fermetures courantes

① Utiliser une fonction comme valeur de retour d'une autre fonction

    function fn1() {
      var a = 2
      function fn2() {
        a++
        console.log(a)
      }
      return fn2
    }
    var f = fn1()
    f()//3
    f()//4

La fonction interne fn2 fait référence à la variable a de la fonction externe fn1, et une fermeture est générée.

Mettez un point d'arrêt sur var a = 2 et a++. L'ensemble du processus d'exécution du programme est le suivant :

1. fn1 et fn2 sont promus en tant que fonctions, et a++ dans fn2 vaut 2 pour le moment.

2. Instruction pour retourner fn2.

3. Exécutez le premier f().

4. Entrez fn2 pour exécuter a++, qui est 3 à ce moment, et la fermeture existe toujours.

5. Une fois l'instruction exécutée, passez au deuxième f().

6. Ensuite, allez directement à fn2() pour exécuter a++, qui est 4 à ce moment.

7. Fin. L'ensemble du processus produit une fermeture car fn1 n'est appelé qu'une seule fois.

S'il n'y a pas de fermeture, la variable a disparaîtra dès que la fonction fn1 sera exécutée. Lorsque f() est appelé plus tard, une erreur sera signalée.

② Passer la fonction en argument à un autre appel de fonction

    function showDelay(msg, time) {
      setTimeout(function () {
        alert(msg)
      }, time)
    }
    showDelay('message', 2000)

 La fonction interne fait référence au message de la fonction externe, ce qui entraîne une fermeture.

5. Le rôle de la clôture

① Utilisez les variables à l'intérieur de la fonction, c'est-à-dire que les variables locales survivent toujours dans la mémoire après l'exécution de la fonction (prolongant le cycle de vie des variables locales) ;

② Rendre les données (variables/fonctions) à l'intérieur de la fonction utilisables (lecture et écriture) en dehors de la fonction.

6. Cycle de vie de la fermeture

① Généré : généré lorsque la définition de fonction interne imbriquée est exécutée (lorsque l'objet fonction est créé, il n'est pas appelé)

② Destruction : lorsque la fonction interne imbriquée devient un objet poubelle

    function fn1() {
      var a = 2//此时闭包就已经产生了(函数提升,内部函数对象已经创建了)
      function fn2() {
        a++
        console.log(a)
      }
      return fn2
    }
    var f = fn1()
    f()//3
    f()//4
    f=null//闭包销毁(包含闭包的函数对象成为了垃圾对象)

7. Demande de clôture

Définissez le module JS :

* fichiers js avec des fonctions spécifiques

* Encapsuler toutes les données et fonctionnalités dans une fonction (privée)

* N'exposer qu'un objet ou une fonction contenant n méthodes

*L'utilisateur du module n'a qu'à appeler la méthode via l'objet exposé par le module pour réaliser la fonction correspondante

fichier code.html :

  <script src="./code.js"></script>
  <script>
    var module = myModule()
    module.doSomething()//doSomething()MY CODE
    module.doOtherthing()//doOtherthing()my code
  </script>

fichier code.js :

function myModule() {
  // 私有数据
  var msg = 'My code'
  // 操作数据的函数
  function doSomething() {
    console.log('doSomething()' + msg.toUpperCase())
  }
  function doOtherthing() {
    console.log('doOtherthing()' + msg.toLowerCase())
  }
  // 向外暴露对象(给外部使用的方法)
  return {
    doSomething: doSomething,
    doOtherthing: doOtherthing
  }
}

Une autre façon d'atteindre:

fichier code.html :

  <script src="./code2.js"></script>
  <script>
    myModule.doSomething()//doSomething()MY CODE
    myModule.doOtherthing()//doOtherthing()my code
  </script>

fichier code.js :

(function myModule() {
  // 私有数据
  var msg = 'My code'
  // 操作数据的函数
  function doSomething() {
    console.log('doSomething()' + msg.toUpperCase())
  }
  function doOtherthing() {
    console.log('doOtherthing()' + msg.toLowerCase())
  }
  // 向外暴露对象(给外部使用的方法)
  window.myModule = {
    doSomething: doSomething,
    doOtherthing: doOtherthing
  }
})()

8. Inconvénients et solutions des fermetures

défaut:

① Après l'exécution de la fonction, les variables locales de la fonction ne sont pas libérées et le temps occupé par la mémoire deviendra plus long

②Il est facile de provoquer des fuites de mémoire

résoudre:

① Si vous pouvez utiliser des fermetures, vous n'en avez pas besoin

② Libération en temps opportun

function fn1(){
  var arr=new Array[1000000]
  function fn2(){
    console.log(arr.length)
  }
  return fn2
}
var f=fn1()
f()
f=null//让内部函数成为垃圾对象,进而回收闭包对象arr

Supplément : débordement de mémoire et fuite de mémoire

1. Débordement de mémoire : Une erreur qui se produit lorsque le programme est en cours d'exécution. Lorsque la mémoire requise par le programme pour s'exécuter dépasse la mémoire restante, une erreur de dépassement de mémoire est générée.

Exemple de code : (n'essayez pas à la légère, cela plantera, hahaha)

    var obj = {}
    for (var i = 0; i < 10000; i++) {
      obj[i] = new Array(10000000)
      console.log('----')
    }

 Mémoire insuffisante

2. Fuite de mémoire : La mémoire occupée n'est pas libérée à temps, la mémoire disponible devient plus petite et le programme peut toujours fonctionner normalement à ce moment.

L'accumulation de fuites de mémoire peut facilement conduire à un débordement de mémoire.

Fuites de mémoire courantes :

① Variables globales inattendues

    function fn() {
      a = 3
      console.log(a)
    }

② La minuterie ou la fonction de rappel qui n'est pas nettoyée à temps

    setInterval(function(){
      console.log('11')
    },1000)

résoudre:

    var timer=setInterval(function(){
      console.log('11')
    },1000)
    clearInterval(timer)//清除定时器

③ fermeture

    function fn1() {
      var a = 4
      function fn2() {
        console.log(++a)
      }
      return fn2
    }
    var f = fn1()
  

résoudre:

    function fn1() {
      var a = 4
      function fn2() {
        console.log(++a)
      }
      return fn2
    }
    var f = fn1()
    f = null

Je suppose que tu aimes

Origine blog.csdn.net/weixin_70443954/article/details/128328047
conseillé
Classement