12 Stimmen

Javascript-Abschluss und Datensichtbarkeit

Ich versuche, meinen Kopf um die Idee der Klassen, Daten Sichtbarkeit und Schließungen (speziell in Javascript) zu wickeln, und ich bin auf der jQuery docs Seite für Typen, es erwähnt, dass Schließungen verwendet werden, um Daten zu verbergen:

Das Muster ermöglicht es Ihnen, Objekte mit Methoden zu erstellen, die mit Daten arbeiten, die für Außenstehende nicht sichtbar sind - die eigentliche Grundlage der objektorientierten Programmierung.

Das Beispiel:

function create() {
  var counter = 0;
  return {
    increment: function() {
      counter++;
    },
    print: function() {
      console.log(counter);
    }
  }
}
var c = create();
c.increment();
c.print(); // 1

Indem die Variable counter mit dem Schlüsselwort var deklariert wird, ist sie bereits innerhalb der Funktions-/Klassendefinition lokal skaliert. Soweit ich weiß, ist sie von außen zunächst nicht zugänglich. Übersehe ich etwas aus Sicht der Datensichtbarkeit?

Zweitens: Gibt es einen Vorteil, die Klasse wie oben zu schreiben und nicht wie unten:

function create() {
  var counter = 0;
  this.increment = function() {
      counter++;
  }
  this.print = function() {
      console.log(counter);
  }
  return this;
}
var c = create();
c.increment();
c.print(); // 1

Wie ich es verstehe, sind diese mehr oder weniger semantisch die gleiche Sache - die erste ist nur mehr "jQuery-Stil". Ich frage mich nur, ob es einen Vorteil oder eine andere Nuance gibt, die ich nicht vollständig aus dem ersten Beispiel zu schätzen weiß. Wenn ich richtig bin, erstellen beide Beispiele Schließungen in, dass sie Zugriff auf Daten außerhalb ihres eigenen Bereichs deklariert sind.

http://docs.jquery.com/Types#Closures

10voto

Kenan Banks Punkte 196831

Zunächst einmal ist es richtig, dass beide Versionen Verschlüsse verwenden.

Die erste Version ist (meiner Meinung nach) sauberer und in modernem Javascript beliebter. Der größte potenzielle Nachteil des ersten Stils ist, dass Sie nicht effektiv Objekte an den Prototyp des Konstruktors zuweisen können, was nützlich (und effizienter) ist, wenn Sie eine Menge der gleichen Objekte erstellen.

Den zweiten Stil habe ich eigentlich noch nie in der Produktion von Javascript gesehen. Normalerweise würden Sie instanziieren create con new statt der Rückkehr this im create() Funktion, etwa so:

function create() {
  var counter = 0;
  this.increment = function() {
      counter++;
  }
  this.print = function() {
      console.log(counter);
  }
}
var c = new create();
c.increment();
c.print(); // 1

0 Stimmen

Und das ist die Art und Weise, wie ich persönlich Objekte am liebsten gestalte, nachdem ich unzählige Techniken ausprobiert habe. Ich denke, das ist einfach viel sauberer und leichter zu verstehen. Aber so bin ich eben :)

4 Stimmen

Kleines Manko: Die Rückgabe von "this" ist gleichbedeutend mit der expliziten Nichtrückgabe von irgendetwas, wenn der new-Operator verwendet wird. Ohne den new-Operator ist "this" der aktuelle Kontext (oft global), und so enden Sie clobbering globalen Variablen.

4voto

Russ Cam Punkte 120837

Durch die Deklaration der Variable counter mit dem Schlüsselwort var deklariert wird, ist sie bereits lokal innerhalb der Funktion/Klasse skaliert Definition. Soweit ich weiß und kann kann, ist sie von außen nicht zugänglich von außen zugänglich. Übersehe ich etwas von der Sichtbarkeit der Daten Perspektive.

Es geht nicht darum, dass die counter Variable nicht von außerhalb der Funktion zugänglich ist, sondern dass sie für die Funktion selbst zugänglich ist. increment y print Funktionen nach create Funktion verlassen hat, was dazu führt, dass Verschlüsse so nützlich.

0 Stimmen

+1 für die Beantwortung des Teils der Frage, dem alle anderen aus irgendeinem Grund ausweichen

2voto

Jason Bunting Punkte 56534

Nun, ich möchte nicht in einen Glaubenskrieg darüber geraten, wie man Objekte in JavaScript erstellt, da einige Leute der Meinung sind, dass es einen richtigen und einen falschen Weg gibt, dies zu tun.

Ich möchte jedoch auf etwas in Ihrem zweiten Code hinweisen, das nicht sehr schmackhaft ist - nämlich die Tatsache, dass Sie neue Eigenschaften für das Objekt in der this Stichwort - ist Ihnen klar, was das für ein Objekt ist? Es ist kein leeres Objekt, es sei denn, Sie verwenden eine Instanziierungssyntax wie diese:

var c = new create();

Wenn Sie das tun, wird die this Schlüsselwort innerhalb des Rumpfes der Konstruktorfunktion ein brandneues Objekt zugewiesen wird, als ob die erste Zeile im Rumpf etwa so lauten würde:

this = {};

Aber wenn Sie anrufen create() als Funktion zu verwenden, wie Sie es in diesem Beispiel tun, ändern Sie den Bereich außerhalb der Funktionsdefinition (wie von @seanmonster in den Kommentaren angedeutet).

0 Stimmen

Sofern die Funktion nicht einem Prototyp oder einem anderen Objekt zugewiesen wird, ist "this" tatsächlich das globale Objekt (Fenster).

0 Stimmen

Hee hee, mein Fehler - die Grammatik Ihres Kommentars ist so subtil, dass ich ihn für das Gegenteil von dem hielt, was er aussagte. Das tut mir leid. Ich muss von diesen komischen Medikamenten loskommen...

0 Stimmen

Ich weiß Ihre Antwort zu schätzen - obwohl sie typischerweise wahr ist, um genauer zu sein, wie ich in meiner jetzt geänderten Antwort dargelegt habe, könnte das Schlüsselwort this etwas anderes als das globale Objekt sein, je nachdem, wo die Funktionsdefinition zu finden ist. Wenn seine "create"-Funktion innerhalb einer Konstruktorfunktion verschachtelt wäre, was durchaus zulässig ist, wäre das this-Schlüsselwort ein anderes als der globale Bereich. Also noch einmal: Ich bin Ihnen dankbar, dass Sie mich darauf aufmerksam gemacht haben, denn das kann eine heikle Angelegenheit sein...

2voto

Itay Maman Punkte 29121

Vergleichen Sie das Beispiel mit diesem Ausschnitt

function create() {
  this.counter = 0;
  this.increment = function() {
      this.counter++;
  };
  this.print = function() {
      console.log(counter);
  }
}

var c = new create();
c.increment();
c.print(); // 1

Wenn also new create() aufgerufen wird, initialisiert es das neue Objekt mit zwei Methoden und einer Instanzvariablen (nämlich: counter). Javascript hat keine Kapselung per se, so dass man auf c.counter wie folgt zugreifen könnte:

var c = new create();
c.increment();
c.counter = 0;
c.print(); // 0

Durch die Verwendung von Closures (wie in Ihren Beispielen gezeigt) ist der Zähler nun kein Instanzfeld mehr, sondern eine lokale Variable. Einerseits kann man von außerhalb der create()-Funktion nicht darauf zugreifen. Andererseits können increment() und print() darauf zugreifen, weil sie den umschließenden Bereich schließen. Wir haben also eine ziemlich gute Emulation der objektweisen Kapselung.

1voto

Joel Coehoorn Punkte 377088

Ihr 2. Beispiel verwendet immer noch Closures, weil die Funktionen increment und print immer noch auf eine Variable wirken, die sonst außerhalb des Geltungsbereichs liegt - zu dem Zeitpunkt, an dem Sie c.increment() die Funktion create wurde bereits beendet.

Das erste Beispiel gefällt mir, weil es das " " vermeidet. this ", und in Javascript " this " kann knifflig sein - es bezieht sich nicht immer auf das, was es anscheinend sollte.

0 Stimmen

Ich bin mir ziemlich sicher, dass die Verwendung der Variablen in der anonymen Funktion bedeutet, dass sie bestehen bleibt, auch wenn die Funktion beendet wurde und die Variable normalerweise verworfen werden würde.

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