Maison  >  Article  >  interface Web  >  Une brève introduction aux fermetures JavaScript

Une brève introduction aux fermetures JavaScript

WBOY
WBOYavant
2023-01-21 06:30:021106parcourir

Cet article vous apporte des connaissances pertinentes sur JavaScript, qui présentent principalement les problèmes liés aux fermetures JavaScript. Il existe de nombreuses versions du concept de fermeture, et différents endroits ont des opinions différentes sur les fermetures. Examinons-les ensemble. tout le monde.

Une brève introduction aux fermetures JavaScript

Qu'est-ce que la fermeture ?

Le concept de fermeture a de nombreuses versions, et différents endroits ont des opinions différentes sur la fermeture

Wikipédia : En informatique, la fermeture (anglais : Closure), également connue sous le nom de fermeture lexicale ou fonction de fermeture lexicale, les fermetures sont une technique de mise en œuvre lexicale liaison dans des langages de programmation prenant en charge des fonctions de première classe.

MDN : Une fermeture est une combinaison d'une fonction et d'une référence à son environnement groupé (environnement lexical, environnement lexical).

Compréhension personnelle :

    Une fermeture est une fonction (renvoie une fonction)
  • La fonction renvoyée enregistre les références de variables externes
Un exemple simple

function fn() {    let num = 1;    return function (n) {        return n + num
    }
}let rFn = fn()let newN = rFn(3) // 4

num La portée de la variable est dans la fonction fn, fonction rFn Mais elle peut accéder à la variable num. Cela signifie que la fonction de fermeture peut accéder à la variable de fonction externe.

log aux fermetures à partir du débogage du navigateur et du code VSCODE NODEJS DÉBUGGING

    BROWSER

Une brève introduction aux fermetures JavaScript

    VS avec Node.js

Une brève introduction aux fermetures JavaScript

see que FN dans la fermeture est la fonction de fermeture, qui enregistre la variable NUM.

Une fermeture classique : mécanisme d'événement monothread + problème de boucle et solution

for (var i = 1; i  {    console.log(i);
  }, i * 1000);
}

Les résultats de sortie sont tous les 6, pourquoi ?

    la boucle for est une tâche synchrone
  • tâche asynchrone setTimeout
boucle for une fois, la tâche asynchrone setTimeout sera ajoutée à la file d'attente des tâches asynchrones du navigateur. Une fois la tâche synchrone terminée, une nouvelle tâche sera extraite du. tâche asynchrone exécutée dans le thread. Puisque setTimeout peut accéder à la variable externe i, lorsque la tâche de synchronisation est terminée, i est devenu 6 et la variable i accessible dans setTimeout est entièrement 6.

Solution 1 : Utilisez l'instruction let

for (var i = 1; i  {    console.log(i);
  }, i * 1000);
}

Solution 2 : Fonction auto-exécutable + fermeture

for (var i = 1; i  {    console.log(i);
  }, i * 1000)
  })(i)
}

Solution 3 : setTimeout passe le troisième paramètre

Le troisième paramètre signifie : des paramètres supplémentaires, une fois la minuterie arrivée. Période, ils le feront être passé en paramètres à la fonction à exécuter

for (var i = 1; i  {    console.log(j);
  }, 1000 * i, i);
}
Closure et fonction curry

function add(num) {  return function (y) {    return num + y;
  };
};let incOneFn = add(1); let n = incOneFn(1);  // 2let decOneFn = add(-1); let m = decOneFn(1); // 0

add Le paramètre de la fonction enregistre la variable de la fonction de fermeture.

Effet réel参数保存了闭包函数变量。

实际作用

在函数式编程闭包有非常重要的作用,lodash 等早期工具函数弥补 javascript 缺陷的工具函数,有大量的闭包的使用场景。

使用场景

  • 创建私有变量
  • 延长变量生命周期

节流函数

防止滚动行为,过度执行函数,必须要节流, 节流函数接受 函数 + 时间作为参数,都是闭包中变量,以下是一个简单 setTimeout 版本:

function throttle(fn, time=300){    var t = null;    return function(){        if(t) return;
        t = setTimeout(() => {
            fn.call(this);
            t = null;
        }, time);
    }
}

防抖函数

一个简单的基于 setTimeout 防抖的函数的实现

function debounce(fn,wait){    var timer = null;    return function(){        if(timer !== null){            clearTimeout(timer);
        }
        timer = setTimeout(fn,wait);
    }
}

React.useCallback 闭包陷阱问题

问题说明:父/子 组件关系, 父子组件都能使用 click 事件同时修改 state 数据, 并且子组件拿到传递下的 props 事件属性,是经过 useCallback

Les fermetures jouent un rôle très important dans la programmation fonctionnelle. Lodash et d'autres premières fonctions d'outils qui compensent les lacunes de JavaScript ont un grand nombre de scénarios d'utilisation pour les fermetures. .

  • Scénarios d'utilisation
Créer des variables privées

Prolonger le cycle de vie des variables

Fonction de limitation

Pour Pour éviter un comportement de défilement et une exécution excessive des fonctions, une limitation est nécessaire. La fonction de limitation accepte function + time comme paramètres, qui sont des variables dans la fermeture. Ce qui suit est un simple setTimeout. version :🎜
import { useState, useCallback, memo } from "react";const ChildWithMemo = memo((props: any) => {  return (    <div>
      <button>Child click</button>
    </div>
  );
});const Parent = () => {  const [count, setCount] = useState(1);  const handleClickWithUseCallback = useCallback(() => {    console.log(count);
  }, []); // 注意这里是不能监听 count, 因为每次变化都会重新绑定,造成造成子组件重新渲染

  return (    <div>
      <div>parent count : {count}</div>
      <button> setCount(count + 1)}>click</button>
      <childwithmemo></childwithmemo>
    </div>
  );
};export default Parent

🎜Fonction anti-shake🎜🎜🎜Une implémentation simple de la fonction anti-shake basée sur setTimeout🎜
import { useState, useCallback, memo, useRef } from "react";const ChildWithMemo = memo((props: any) => {  console.log("rendered children")  return (    <div>
      <button> props.countRef.current()}>Child click</button>
    </div>
  );
});const Parent = () => {  const [count, setCount] = useState(1);  const countRef = useRef<any>(null)

  countRef.current = () => {    console.log(count);
  }  return (    <div>
      <div>parent count : {count}</div>
      <button> setCount(count + 1)}>click</button>
      <childwithmemo></childwithmemo>
    </div>
  );
};export default Parent</any>

React .useCallback Problème de piège de fermeture🎜🎜Description du problème : relation entre les composants Parent/Enfant, les composants parent et enfant peuvent utiliser l'événement click pour modifier les données d'état en même temps, et le composant enfant obtient l'événement props transmis attribut via useCallback optimisé. Autrement dit, cette fonction optimisée a un piège de fermeture (la valeur de l'état initial est toujours enregistrée) 🎜rrreee🎜🎜ChildWithMemo utilise memo pour l'optimisation, 🎜🎜handleClickWithUseCallback utilise useCallback pour l'optimisation🎜🎜🎜🎜Le problème est que lorsque le sous-composant est cliqué, la sortie Le compte est la valeur initiale (fermée). 🎜🎜🎜La solution est d'utiliser useRef pour enregistrer la fonction de variable de fonctionnement : 🎜rrreee🎜En réponse à ce problème, React a une fois approuvé la proposition de la communauté d'ajouter useEvent, mais plus tard, le problème sémantique useEvent a été abandonné pour l'optimisation du rendu, React a adopté. une solution d'optimisation de compilation. En fait, des problèmes similaires se produiront également dans useEffect. Faites attention aux pièges de fermeture lors de son utilisation. 🎜

Problèmes de performances

  • Ne définissez pas les fermetures à volonté. Une fois définies, vous devez trouver un emplacement approprié pour la destruction. Étant donné que les variables de fermeture sont stockées en mémoire et ne seront pas détruites, elles occupent une grande quantité de mémoire.

Utilisez la fonction du panneau Chrome Chronologie + panneau Profils

  1. Ouvrez les outils de développement, sélectionnez le panneau Chronologie
  2. Vérifiez la mémoire dans le champ Capture en haut
  3. Cliquez sur le bouton d'enregistrement dans le coin supérieur gauche.
  4. Effectuez diverses opérations sur la page pour simuler l'utilisation des utilisateurs.
  5. Après un certain temps, cliquez sur le bouton d'arrêt dans la boîte de dialogue et l'utilisation de la mémoire pendant cette période sera affichée sur le panneau.

【Recommandations associées : Tutoriel vidéo JavaScript, front-end web

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer