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();

19voto

maerics Punkte 141984

Vor allem in der Sprache JavaScript (oder ECMAScript) sind Closures nützlich, um die Implementierung von Funktionen zu verbergen und gleichzeitig die Schnittstelle zu offenbaren.

Stellen Sie sich zum Beispiel vor, Sie schreiben eine Klasse von Datums-Utility-Methoden und wollen den Benutzern die Möglichkeit geben, die Namen der Wochentage anhand eines Indexes nachzuschlagen, aber Sie wollen nicht, dass sie das Array der Namen, das Sie unter der Haube verwenden, ändern können.

var dateUtil = {
  weekdayShort: (function() {
    var days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
    return function(x) {
      if ((x != parseInt(x)) || (x < 1) || (x > 7)) {
        throw new Error("invalid weekday number");
      }
      return days[x - 1];
    };
  }())
};

Beachten Sie, dass die days Array könnte einfach als eine Eigenschaft der dateUtil Objekt, aber dann wäre es für die Benutzer des Skripts sichtbar und sie könnten es sogar ändern, wenn sie wollten, ohne Ihren Quellcode zu benötigen. Da es jedoch von der anonymen Funktion eingeschlossen ist, die die Datumsabfragefunktion zurückgibt, ist es nur für die Abfragefunktion zugänglich, so dass es jetzt manipulationssicher ist.

8voto

alex Punkte 457905

Es gibt einen Abschnitt über Praktische Verschlüsse am Mozilla-Entwickler-Netzwerk .

7voto

Luke Schlangen Punkte 3418

Hier habe ich einen Gruß, den ich mehrmals sagen möchte. Wenn ich einen Abschluss erstelle, kann ich diese Funktion einfach aufrufen, um die Ansage aufzunehmen. Wenn ich den Abschluss nicht erstelle, muss ich jedes Mal meinen Namen eingeben.

Ohne einen Verschluss ( https://jsfiddle.net/lukeschlangen/pw61qrow/3/ ):

function greeting(firstName, lastName) {
  var message = "Hello " + firstName + " " + lastName + "!";
  console.log(message);
}

greeting("Billy", "Bob");
greeting("Billy", "Bob");
greeting("Billy", "Bob");
greeting("Luke", "Schlangen");
greeting("Luke", "Schlangen");
greeting("Luke", "Schlangen");

Mit einem Verschluss ( https://jsfiddle.net/lukeschlangen/Lb5cfve9/3/ ):

function greeting(firstName, lastName) {
  var message = "Hello " + firstName + " " + lastName + "!";

  return function() {
    console.log(message);
  }
}

var greetingBilly = greeting("Billy", "Bob");
var greetingLuke = greeting("Luke", "Schlangen");

greetingBilly();
greetingBilly();
greetingBilly();
greetingLuke();
greetingLuke();
greetingLuke();

7voto

EdwardG Punkte 1781

Wenn Sie mit dem Konzept der Instanziierung einer Klasse im objektorientierten Sinne (d. h. der Erstellung eines Objekts dieser Klasse) vertraut sind, sind Sie dem Verständnis von Closures schon sehr nahe.

Stellen Sie es sich so vor: Wenn Sie zwei Person-Objekte instanziieren, wissen Sie, dass die Klassenvariable "Name" nicht zwischen den Instanzen geteilt wird; jedes Objekt hat seine eigene "Kopie". Ähnlich verhält es sich, wenn Sie einen Abschluss erstellen, der freie Variable ('calledCount' in Ihrem Beispiel oben) ist an die 'Instanz' der Funktion gebunden.

Ich denke, Ihr konzeptioneller Sprung wird durch die Tatsache behindert, dass jede Funktion/jeder Abschluss, die/der von der warnUser-Funktion zurückgegeben wird (nebenbei: das ist eine übergeordnete Funktion ) Closure bindet 'calledCount' mit demselben Initialwert (0), während es bei der Erstellung von Closures oft sinnvoller ist, unterschiedliche Initialisierer an die übergeordnete Funktion zu übergeben, ähnlich wie bei der Übergabe unterschiedlicher Werte an den Konstruktor einer Klasse.

Nehmen wir also an, dass Sie die Sitzung des Benutzers beenden wollen, wenn "calledCount" einen bestimmten Wert erreicht hat; Sie könnten dafür unterschiedliche Werte wollen, je nachdem, ob die Anfrage aus dem lokalen Netz oder dem großen bösen Internet kommt (ja, das ist ein erfundenes Beispiel). Um dies zu erreichen, könnten Sie unterschiedliche Anfangswerte für calledCount in warnUser übergeben (z.B. -3, oder 0?).

Ein Teil des Problems in der Literatur liegt in der Nomenklatur, mit der sie beschrieben werden ("lexical scope", "free variables"). Lassen Sie sich davon nicht täuschen, Closures sind einfacher, als es den Anschein hat... prima facie ;-)

5voto

Abhilash KK Punkte 438

Hier habe ich ein einfaches Beispiel für das Verschlusskonzept, das wir für unsere E-Commerce-Website oder viele andere auch verwenden können.

Ich füge meinen JSFiddle-Link mit dem Beispiel hinzu. Es enthält eine kleine Produktliste mit drei Artikeln und einen Warenkorbzähler.

JSFiddle

// Counter closure implemented function;
var CartCouter = function(){
  var counter = 0;

  function changeCounter(val){
      counter += val
  }

  return {
      increment: function(){
        changeCounter(1);
    },
    decrement: function(){
      changeCounter(-1);
    },
    value: function(){
      return counter;
    }
  }
}

var cartCount = CartCouter();

function updateCart() {
  document.getElementById('cartcount').innerHTML = cartCount.value();
}

var productlist = document.getElementsByClassName('item');
for(var i = 0; i< productlist.length; i++){
  productlist[i].addEventListener('click', function(){
    if(this.className.indexOf('selected') < 0){
      this.className += " selected";
      cartCount.increment();
      updateCart();
    }
    else{
      this.className = this.className.replace("selected", "");
      cartCount.decrement();
      updateCart();
    }
  })
}

.productslist{
  padding: 10px;
}
ul li{
  display: inline-block;
  padding: 5px;
  border: 1px solid #DDD;
  text-align: center;
  width: 25%;
  cursor: pointer;
}
.selected{
  background-color: #7CFEF0;
  color: #333;
}
.cartdiv{
  position: relative;
  float: right;
  padding: 5px;
  box-sizing: border-box;
  border: 1px solid #F1F1F1;
}

<div>
    <h3>
        Practical use of a JavaScript closure concept/private variable.
    </h3>

    <div class="cartdiv">
        <span id="cartcount">0</span>
    </div>

    <div class="productslist">
        <ul>
            <li class="item">Product 1</li>
            <li class="item">Product 2</li>
            <li class="item">Product 3</li>
        </ul>
    </div>
</div>

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