Heim  >  Artikel  >  Web-Frontend  >  Eine kurze Einführung in JavaScript-Verschlüsse

Eine kurze Einführung in JavaScript-Verschlüsse

WBOY
WBOYnach vorne
2023-01-21 06:30:021106Durchsuche

Dieser Artikel bringt Ihnen relevantes Wissen über JavaScript, das hauptsächlich Probleme im Zusammenhang mit JavaScript-Abschlüssen aufzeigt. Es gibt viele Versionen des Verschlusskonzepts, und verschiedene Orte haben unterschiedliche Meinungen zu Abschlüssen. Ich hoffe, es hilft alle.

Eine kurze Einführung in JavaScript-Verschlüsse

Was ist Schließung?

Das Konzept der Schließung hat viele Versionen, und verschiedene Orte haben unterschiedliche Meinungen über Schließung

Wikipedia: In der Informatik ist Schließung (englisch: Schließung), auch bekannt als Lexikalische Schließung oder Funktionsschließungen, eine Technik zur Implementierung lexikalischer Bindung in Programmiersprachen, die erstklassige Funktionen unterstützen.

MDN: Ein Abschluss ist eine Kombination aus einer Funktion und einem Verweis auf ihre gebündelte Umgebung (lexikalische Umgebung, lexikalische Umgebung).

Persönliches Verständnis:

    Ein Abschluss ist eine Funktion (gibt eine Funktion zurück)
  • Die zurückgegebene Funktion speichert externe Variablenreferenzen
Ein einfaches Beispiel

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

num Der Variablenbereich befindet sich in der fn-Funktion, rFn-Funktion Aber es kann auf die Variable num zugreifen. Dies bedeutet, dass die Abschlussfunktion auf die externe Funktionsvariable zugreifen kann.

Sehen Sie sich Schließungen beim Browser-Debugging und VSCode Nodejs-Debugging an.

Ein klassischer Abschluss: Single-Threaded-Ereignismechanismus + Schleifenproblem und Lösung
    for (var i = 1; i  {    console.log(i);
      }, i * 1000);
    }
  • Die Ausgabeergebnisse sind alle 6, warum?
  • for-Schleife ist eine synchrone Aufgabe Eine kurze Einführung in JavaScript-Verschlüsse

    setTimeout asynchrone Aufgabe
    • for-Schleife Einmal wird die asynchrone Aufgabe setTimeout zur asynchronen Aufgabenwarteschlange des Browsers hinzugefügt. Nachdem die synchrone Aufgabe abgeschlossen ist, wird eine neue Aufgabe aus der Warteschlange für asynchrone Aufgaben hinzugefügt Asynchrone Aufgabe. Wird im Thread ausgeführt. Da setTimeout auf die externe Variable i zugreifen kann, ist i nach Abschluss der Synchronisierungsaufgabe 6, und die Variable i, auf die in setTimeout zugegriffen werden kann, ist alle 6.

    Lösung 1: Let-Anweisung verwendenEine kurze Einführung in JavaScript-Verschlüsse

    for (var i = 1; i  {    console.log(i);
      }, i * 1000);
    }
    Lösung 2: Selbstausführende Funktion + Abschluss

    for (var i = 1; i  {    console.log(i);
      }, i * 1000)
      })(i)
    }
    Lösung 3: setTimeout übergibt den dritten Parameter

    Der dritte Parameter bedeutet: zusätzliche Parameter, sobald der Timer ankommt als Parameter an die auszuführende Funktion übergeben werden

      for (var i = 1; i  {    console.log(j);
        }, 1000 * i, i);
      }
    • Abschluss und Funktionscurry
    • 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 Der Parameter der Funktion speichert die Variable der Abschlussfunktion.
    • Tatsächliche Wirkung

      Abschlüsse spielen eine sehr wichtige Rolle in der funktionalen Programmierung. Lodash und andere frühe Toolfunktionen, die die Mängel von JavaScript ausgleichen, weisen eine große Anzahl von Verwendungsszenarien für Abschlüsse auf .

      Nutzungsszenarien

      Private Variablen erstellen

      Variablenlebenszyklus verlängern

      Drosselungsfunktion

      Zu Um das Scrollverhalten und die übermäßige Ausführung von Funktionen zu verhindern, ist eine Drosselung erforderlich. Die Drosselungsfunktion akzeptiert function + time als Parameter, die Variablen im Abschluss sind Version:参数保存了闭包函数变量。

      实际作用

      在函数式编程闭包有非常重要的作用,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

      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

      Anti-Shake-Funktion
      • Eine einfache Implementierung der Anti-Shake-Funktion basierend auf 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-Closure-Trap-Problem

      Problembeschreibung: Parent/Child-Komponentenbeziehung, übergeordnete und untergeordnete Komponenten können das Click-Ereignis verwenden, um Statusdaten gleichzeitig zu ändern, und die untergeordnete Komponente erhält das übergebene Props-Ereignis Attribut durch useCallback optimiert. Das heißt, diese optimierte Funktion verfügt über eine Abschlussfalle (der Anfangszustandswert wird immer gespeichert). Wenn Sie darauf klicken, wird die Ausgabe angezeigt. Die Anzahl ist der Anfangswert (geschlossen).

      Die Lösung besteht darin, useRef zum Speichern der Betriebsvariablenfunktion zu verwenden:
      rrreee

      Als Reaktion auf dieses Problem genehmigte React einmal die Lösung der Community, useEvent hinzuzufügen, aber später wurde das semantische Problem von useEvent aufgegeben. Zur Rendering-Optimierung wurde React übernommen eine Kompilierungsoptimierungslösung. Tatsächlich treten ähnliche Probleme auch bei useEffect auf. Achten Sie bei der Verwendung auf Verschlussfallen.

      Leistungsprobleme

      • Definieren Sie Schließungen nicht nach Belieben. Sobald Sie sie definiert haben, müssen Sie einen geeigneten Ort für die Zerstörung finden. Da die Variablen des Abschlusses im Speicher gespeichert werden und nicht zerstört werden, belegen sie viel Speicher.

      Verwenden Sie die Chrome-Panel-Funktion Timeline + Profile-Panel.

      1. Öffnen Sie die Entwicklertools, wählen Sie das Timeline-Panel aus.
      2. Überprüfen Sie den Speicher im Feld Capture oben.
      3. Klicken Sie auf die Aufnahmeschaltfläche in der oberen linken Ecke.
      4. Führen Sie verschiedene Vorgänge auf der Seite aus, um die Benutzernutzung zu simulieren.
      5. Klicken Sie nach einer gewissen Zeit auf die Schaltfläche „Stopp“ im Dialogfeld. Die Speichernutzung während dieses Zeitraums wird auf dem Bedienfeld angezeigt.

      【Verwandte Empfehlungen: JavaScript-Video-Tutorial, Web-Frontend

      Das obige ist der detaillierte Inhalt vonEine kurze Einführung in JavaScript-Verschlüsse. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

      Stellungnahme:
      Dieser Artikel ist reproduziert unter:juejin.im. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen