354 Stimmen

Was ist eine praktische Anwendung für eine Schließung in JavaScript?

Ich bin Versuch Ich tue mich schwer damit, JavaScript-Schließungen zu verstehen.

Ich verstehe, dass durch die Rückgabe einer inneren Funktion, wird es Zugriff auf jede Variable in seiner unmittelbaren Eltern definiert haben.

Wo wäre dies für mich von Nutzen? Vielleicht habe ich es noch nicht ganz begriffen. Die meisten der Beispiele, die ich online gesehen habe bieten keinen realen Code, sondern nur vage Beispiele.

Kann mir jemand zeigen, wie ein Verschluss in der Praxis eingesetzt wird?

Ist dies zum Beispiel eine?

var warnUser = function (msg) {
    var calledCount = 0;
    return function() {
       calledCount++;
       alert(msg + '\nYou have been warned ' + calledCount + ' times.');
    };
};

var warnForTamper = warnUser('You can not tamper with our HTML.');
warnForTamper();
warnForTamper();

354voto

Angenommen, Sie möchten Zählen, wie oft der Benutzer eine Schaltfläche angeklickt hat auf einer Webseite.

Hierfür lösen Sie eine Funktion auf onclick Ereignis der Schaltfläche, um den Zählerstand der Variablen zu aktualisieren

<button onclick="updateClickCount()">click me</button>

Nun könnte es viele Ansätze geben wie:

  1. Sie könnten eine globale Variable und eine Funktion zur Erhöhung der Zähler :

     var counter = 0;
    
     function updateClickCount() {
         ++counter;
         // Do something with counter
     }

    Der Haken an der Sache ist jedoch, dass kann jedes Skript auf der Seite den Zähler ändern, ohne den Aufruf updateClickCount() .


  1. Nun denken Sie vielleicht daran, die Variable innerhalb der Funktion zu deklarieren:

     function updateClickCount() {
         var counter = 0;
         ++counter;
         // Do something with counter
     }

    Aber, hey! Jedes Mal updateClickCount() Funktion aufgerufen wird, wird die Zähler wird wieder auf 1 gesetzt.


  1. Nachdenken über verschachtelte Funktionen ?

    Verschachtelte Funktionen haben Zugriff auf den Bereich "über" ihnen.

    In diesem Beispiel wird die innere Funktion updateClickCount() hat Zugriff auf die Zählervariable in der übergeordneten Funktion countWrapper() :

     function countWrapper() {
         var counter = 0;
         function updateClickCount() {
             ++counter;
             // Do something with counter
         }
         updateClickCount();
         return counter;
     }

    Dies hätte das Dilemma des Zählers lösen können, wenn man die updateClickCount() Funktion von außen und Sie müssen auch einen Weg finden, die counter = 0 nur einmal, nicht jedes Mal.


  1. Die Schließung ist die Rettung! (selbstanregende Funktion) :

     var updateClickCount = (function(){
         var counter = 0;
    
         return function(){
             ++counter;
             // Do something with counter
         }
     })();

    Die selbstaufrufende Funktion wird nur einmal ausgeführt. Sie setzt die counter auf Null (0) und gibt einen Funktionsausdruck zurück.

    Auf diese Weise updateClickCount wird zu einer Funktion. Der "wunderbare" Teil ist, dass sie auf den Zähler im übergeordneten Bereich zugreifen kann.

    Dies wird als JavaScript-Verschluss . Sie ermöglicht es, dass eine Funktion " privat Variablen".

    En counter ist durch den Geltungsbereich der anonymen Funktion geschützt und kann nur mit dem Befehl updateClickCount() Funktion!

Ein anschaulicheres Beispiel für Verschlüsse

<script>
var updateClickCount = (function(){
    var counter = 0;

    return function(){
        ++counter;
        document.getElementById("spnCount").innerHTML = counter;
    }
})();
</script>

<html>
<button onclick="updateClickCount()">click me</button>
<div> you've clicked
    <span id="spnCount"> 0 </span> times!
</div>
</html>

Referenz: _JavaScript-Schließungen_

283voto

Francisco Soto Punkte 10131

Ich habe Verschlüsse verwendet, um Dinge zu tun wie:

a = (function () {
    var privatefunction = function () {
        alert('hello');
    }

    return {
        publicfunction : function () {
            privatefunction();
        }
    }
})();

Wie Sie dort sehen können, a ist jetzt ein Objekt, mit einer Methode publicfunction ( a.publicfunction() ), die aufruft privatefunction die nur innerhalb des Verschlusses existiert. Sie können no aufrufen privatefunction direkt (d.h. a.privatefunction() ), nur publicfunction() .

Es ist ein Minimalbeispiel, aber vielleicht sehen Sie einen Nutzen darin? Wir haben dies verwendet, um öffentliche/private Methoden zu erzwingen.

73voto

Marcelo Cantos Punkte 173498

Das von Ihnen angeführte Beispiel ist ausgezeichnet. Closures sind ein Abstraktionsmechanismus, der es Ihnen ermöglicht, Anliegen sehr sauber zu trennen. In Ihrem Beispiel geht es um die Trennung von Instrumentierung (Zählen von Aufrufen) und Semantik (eine API mit Fehlerberichten). Andere Anwendungen sind:

  1. Übergabe von parametrisiertem Verhalten an einen Algorithmus (klassische Programmierung höherer Ordnung):

    function proximity_sort(arr, midpoint) {
        arr.sort(function(a, b) { a -= midpoint; b -= midpoint; return a*a - b*b; });
    }
  2. Simulation der objektorientierten Programmierung:

    function counter() {
        var a = 0;
        return {
            inc: function() { ++a; },
            dec: function() { --a; },
            get: function() { return a; },
            reset: function() { a = 0; }
        }
    }
  3. Implementierung exotischer Ablaufsteuerungen, wie z.B. jQuery's Event Handling und AJAX APIs.

39voto

Mohd Asim Suhail Punkte 2100

JavaScript-Schließungen können verwendet werden, um Folgendes zu implementieren Drosselklappe y Entprellung Funktionalität in Ihrer Anwendung.

Drosselung

Die Drosselung legt fest, wie oft eine Funktion in einem bestimmten Zeitraum maximal aufgerufen werden kann. Wie in "führe diese Funktion höchstens einmal alle 100 Millisekunden aus".

Código:

const throttle = (func, limit) => {
  let isThrottling
  return function() {
    const args = arguments
    const context = this
    if (!isThrottling) {
      func.apply(context, args)
      isThrottling = true
      setTimeout(() => isThrottling = false, limit)
    }
  }
}

Entprellung

Die Entprellung legt fest, dass eine Funktion erst dann wieder aufgerufen werden darf, wenn eine bestimmte Zeitspanne vergangen ist, ohne dass sie aufgerufen wurde. Zum Beispiel: "Führe diese Funktion nur aus, wenn 100 Millisekunden vergangen sind, ohne dass sie aufgerufen wurde."

Código:

const debounce = (func, delay) => {
  let debouncing
  return function() {
    const context = this
    const args = arguments
    clearTimeout(debouncing)
    debouncing = setTimeout(() => func.apply(context, args), delay)
  }
}

Wie Sie sehen können, halfen Schließungen bei der Implementierung von zwei schönen Funktionen, die jede Webanwendung haben sollte, um eine reibungslose UI-Funktionalität zu bieten.

21voto

Andy E Punkte 324972

Ja, das ist ein gutes Beispiel für einen nützlichen Abschluss. Der Aufruf von warnUser erzeugt die calledCount Variable in ihrem Bereich und gibt eine anonyme Funktion zurück, die in der warnForTamper variabel. Da es immer noch eine Schließung gibt, die die Variable calledCount verwendet, wird sie beim Beenden der Funktion nicht gelöscht, so dass jeder Aufruf der Funktion warnForTamper() erhöht die untersuchte Variable und meldet den Wert.

Das häufigste Problem, das ich auf Stack Overflow sehe, ist, dass jemand die Verwendung einer Variablen, die bei jeder Schleife erhöht wird, "verzögern" möchte, aber da die Variable scoped ist, würde jeder Verweis auf die Variable nach dem Ende der Schleife erfolgen, was zum Endzustand der Variablen führt:

for (var i = 0; i < someVar.length; i++)
    window.setTimeout(function () {
        alert("Value of i was "+i+" when this timer was set" )
    }, 10000);

Dies würde dazu führen, dass jede Ausschreibung denselben Wert von i den Wert, auf den er am Ende der Schleife erhöht wurde. Die Lösung besteht darin, eine neue Closure zu erstellen, einen separaten Bereich für die Variable. Dies kann mit einer sofort ausgeführten anonymen Funktion geschehen, die die Variable erhält und ihren Zustand als Argument speichert:

for (var i = 0; i < someVar.length; i++)
    (function (i) {
        window.setTimeout(function () {
            alert("Value of i was " + i + " when this timer was set")
        }, 10000);
    })(i);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X