Comprensión de los cierres en JavaScript

Tabla de contenido

1. Presente:

2. ¿Qué es un cierre?

3. Condiciones para la generación del cierre:

4. Cierres comunes

5. El papel del cierre

6. Ciclo de vida del cierre

7. Aplicación del cierre

8. Inconvenientes y soluciones de los cierres

Suplemento: desbordamiento de memoria y pérdida de memoria


1. Presente:

Ahora tenemos un requisito: hay tres botones, y cuando se hace clic en un botón, aparece "se hace clic en el botón n".

Código:

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

De esta manera de escribir, no importa en qué botón se haga clic, aparecerá el "4to botón".

Esto se debe a que el evento de clic de botón solo se llama cuando se activa. Cuando se ejecuta el código console.log(`el botón ${i + 1}`) y se ejecuta el evento de clic, se ejecuta el bucle for. Todo el proceso finalmente produce solo una i, en este momento el valor de i se ha convertido en 3, sin importar en qué botón se haga clic, i = 3, por lo que genera 3 + 1 = 4, que es el "cuarto botón". En otras palabras, durante los primeros 3 ciclos, el evento de clic no se ejecutó.

Podemos modificar el código:

Registramos i, correspondemos a i de cada btn y conocemos el valor del índice i de cada botón btn. De esta manera, al hacer clic en el botón se generará el valor correspondiente.

    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}个按钮`)
      }
    }

En este momento, la salida puede ser normal.

Por supuesto, hay otra forma de poner la declaración de salida en una función de autoinvocación anónima.

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

En este momento, también puede salir normalmente.

 Esto utiliza cierres.

2. ¿Qué es un cierre?

Se produce un cierre cuando una función interna anidada (secundaria) se refiere a una variable (función) de una función externa anidada (principal).

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

Es decir, la función fn2 anidada interna se refiere a la variable a en la función fn1 externa y fn2 genera un cierre en este momento.

Entonces, ¿qué son exactamente los cierres?

①Comprensión 1: Closure es una función interna anidada, aquí está la función fn2.

②Concepto 2: El objeto que contiene la variable referenciada (función), es decir, la variable referenciada en la función interna fn2.

Nota: Los cierres existen dentro de funciones internas anidadas.

3. Condiciones para la generación del cierre:

① Anidamiento de funciones

②La función interna hace referencia a los datos de la función externa (variable/función)

③ Ejecutar y llamar funciones externas

4. Cierres comunes

① Usar una función como valor de retorno de otra función

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

La función interna fn2 hace referencia a la variable a de la función externa fn1, y se genera un cierre.

Coloque un punto de interrupción en var a = 2 y a ++.Todo el proceso de ejecución del programa es el siguiente:

1. fn1 y fn2 se promocionan como funciones, y a++ en fn2 es 2 en este momento.

2. Declaración para devolver fn2.

3. Ejecute la primera f().

4. Ingrese fn2 para ejecutar a++, que es 3 en este momento, y el cierre aún existe.

5. Después de ejecutar la instrucción, vaya a la segunda f().

6. Luego, vaya directamente a fn2() para ejecutar a++, que es 4 en este momento.

7. Fin. Todo el proceso produce un cierre porque fn1 solo se llama una vez.

Si no hay cierre, la variable a desaparecerá tan pronto como se ejecute la función fn1. Cuando f() se llame más tarde, se informará un error.

② Pasar la función como argumento a otra llamada de función

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

 La función interna hace referencia al mensaje de la función externa, lo que resulta en un cierre.

5. El papel del cierre

① Usar las variables dentro de la función, es decir, las variables locales aún sobreviven en la memoria después de ejecutar la función (extendiendo el ciclo de vida de las variables locales);

② Hacer que los datos (variables/funciones) dentro de la función sean operables (lectura y escritura) fuera de la función.

6. Ciclo de vida del cierre

① Generado: Generado cuando se ejecuta la definición de función interna anidada (cuando se crea el objeto de función, no se llama)

② Destrucción: cuando la función interna anidada se convierte en un objeto basura

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

7. Aplicación del cierre

Defina el módulo JS:

* archivos js con funciones específicas

* Encapsular todos los datos y la funcionalidad dentro de una función (privada)

* Solo exponga un objeto o función que contenga n métodos

*El usuario del módulo solo necesita llamar al método a través del objeto expuesto por el módulo para realizar la función correspondiente

archivo código.html:

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

archivo código.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
  }
}

Otra forma de lograr:

archivo código.html:

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

archivo código.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. Inconvenientes y soluciones de los cierres

defecto:

① Después de ejecutar la función, las variables locales en la función no se liberan y el tiempo ocupado por la memoria será más largo

②Es fácil causar fugas de memoria

resolver:

① Si puede usar cierres, no los necesita

② Lanzamiento oportuno

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

Suplemento: desbordamiento de memoria y pérdida de memoria

1. Desbordamiento de memoria : un error que ocurre cuando el programa se está ejecutando. Cuando la memoria requerida por el programa para ejecutarse excede la memoria restante, se generará un error de desbordamiento de memoria.

Ejemplo de código: (No lo intentes a la ligera, se bloqueará, jajaja)

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

 Sin memoria

2. Pérdida de memoria : la memoria ocupada no se libera a tiempo, la memoria disponible se vuelve más pequeña y el programa aún puede ejecutarse normalmente en este momento.

La acumulación de fugas de memoria puede conducir fácilmente a un desbordamiento de memoria.

Fugas de memoria comunes:

① Variable global inesperada

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

② La función de temporizador o devolución de llamada que no se limpia a tiempo

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

resolver:

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

③ cierre

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

resolver:

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

Supongo que te gusta

Origin blog.csdn.net/weixin_70443954/article/details/128328047
Recomendado
Clasificación