Verschlüsse werden im Land von JavaScript oft als eine arkane Kunst angesehen. Einmal beherrscht, können Sie wirklich erstaunliches JavaScript schreiben. In diesem Artikel erfahren Sie mehr über die Magie von JavaScript-Verschlüssen.
Eine der Schlüsselwahrheiten von JavaScript ist das alles ist ein Objekt. Dies beinhaltet natürlich Funktionen.
Ein Abschluss ist nichts anderes als ein Funktionsobjekt mit einem zugehörigen Gültigkeitsbereich, in dem die Variablen der Funktion aufgelöst werden.
Verschlüsse erhalten ihren Namen aufgrund ihrer Art und Weise schließen über ihren Inhalt. Beachten Sie folgendes JavaScript:
topping = "anchovi"; Funktion pizzaParty (numSlices) var topping = "pepperoni", innerFunction = function () var topping = "ham"; console.log ("... aber setze" + topping + "in" + numSlices + "Slices"); ; console.log ("Diese Pizza dreht sich alles um das" + Topping "); innerFunction (); PizzaParty (3);
Wenn Sie Ihre Lieblingskonsole öffnen und den bösen Jungen ausführen, werden Sie mit einer köstlichen Nachricht begrüßt: "Diese Pizza dreht sich alles um die Peperoni ... Aber legen Sie Schinken auf 3 Scheiben." Dieses Beispiel veranschaulicht einige Schlüsselkonzepte von JavaScript, die für den Abschluss von Schließungen von entscheidender Bedeutung sind.
Wie viele Funktionsobjekte enthält der obige Code? Nun, wir haben unsere Pizza Party
Funktion und verschachtelt in dieser Funktion ist innerFunction
. Mathematik war nicht immer meine Stärke, aber 1 + 1 = 2
in meinem Buch. Jedes Funktionsobjekt verfügt über einen eigenen Satz von Variablen, die in jeder Funktion aufgelöst werden Umfang.
Verschlüsse können nicht vollständig verstanden werden, ohne dass der Geltungsbereich fest verankert ist. Durch den Geltungsbereichsmechanismus von JavaScript kann jede Funktion ihre eigene haben Belag
variabel, und ohne sie könnten wir zu viel Peperoni haben, zu wenig Schinken oder * keuchen * ... einige Sardellen auf unserer Pizza-Party. Lassen Sie uns eine kurze Illustration verwenden, um diese Idee besser zu veranschaulichen.
Funktionen werden mit dem Gültigkeitsbereich ausgeführt, der zum Zeitpunkt der Definition der Funktion gültig war. Es hat nichts mit dem Gültigkeitsbereich zu tun, wenn die Funktion aufgerufen wird.
Die grünen Pfeile zeigen an, dass die Zugänglichkeit von außen funktioniert. Innerhalb des Bereichs außerhalb einer Funktion definierte Variablen sind von innen her zugänglich.
Wenn wir das weglassen würden Belag
variabel von innen Pizza Party
Funktion, dann bekämen wir eine Nachricht wie "Diese Pizza dreht sich alles um den Anchovi", aber da Pizza Party
hat ein Belag
variabel in seinem eigenen Bereich; Diese salzigen Trottel kommen niemals in die Nähe unserer Pizza-Party.
Ebenso die numSlices
Parameter ist von innen zugänglich innerFunction
weil es im obigen Bereich definiert ist - in diesem Fall der Umfang von Pizza Party
.
Die roten Pfeile zeigen an, dass Variablen im Gültigkeitsbereich einer Funktion außerhalb dieser Funktion niemals zugänglich sind. Dies ist nur der Fall, wenn eine Variable eine der folgenden Bedingungen erfüllt:
var
Schlüsselwort wird verwendet. Das auslassen var
Wenn ein Schlüsselwort beim Festlegen einer Variablen festgelegt wird, setzt JavaScript die nächstgelegene benannte Variable in äußeren Funktionen bis zum globalen Gültigkeitsbereich. An unserem Beispiel also dem Schinken Belag
im innerFunction
kann nicht von erreicht werden Pizza Party
, und die Peperoni Belag
im Pizza Party
ist im globalen Geltungsbereich, in dem die Sardellen leben, nicht zugänglich.
Lexikalischer Bereich bedeutet, dass Funktionen unter Verwendung des gültigen Gültigkeitsbereichs ausgeführt werden, als die Funktion ausgeführt wurde definiert. Es hat nichts mit dem Gültigkeitsbereich zu tun, wenn die Funktion aufgerufen wird. Diese Tatsache ist entscheidend, um die Macht der Verschlüsse zu erschließen.
Nachdem wir nun verstanden haben, was eine Schließung ist und welche Bedeutung Schließungen haben, wollen wir uns mit einigen klassischen Anwendungsfällen beschäftigen.
Verschlüsse sind das So können Sie Ihren Code vor der Öffentlichkeit verbergen. Mit Verschlüssen können Sie leicht private Mitglieder haben, die von der Außenwelt abgeschirmt sind:
(function (exportiert) function myPrivateMultiplyFunction (num, num2) return num * num2; // entspricht window.multiply = Funktion (num1, num2) … exports.multiply = Funktion (num1, num2) console.log (myPrivateMultiplyFunction (num1, num2));) (Fenster);
Mit Verschlüssen können Sie leicht private Mitglieder haben, die von der Außenwelt abgeschirmt sind.
Lass es uns brechen. Unser Funktionsobjekt auf oberster Ebene ist eine anonyme Funktion:
(Funktion (Exporte) ) (Fenster);
Wir rufen diese anonyme Funktion sofort auf. Wir übergeben den globalen Kontext (Fenster
in diesem Fall) können wir also eine öffentliche Funktion "exportieren", aber alles andere ausblenden. Weil die Funktion myPrivateMultiplyFunction
ist eine verschachtelte Funktion, sie existiert nur im Rahmen unserer Schließung; Daher können wir es überall in diesem Bereich und nur in diesem Bereich verwenden.
JavaScript enthält einen Verweis auf unsere private Funktion zur Verwendung in der Multiplikationsfunktion myPrivateMultiplyFunction
ist außerhalb der Schließung nicht zugänglich. Lass uns das ausprobieren:
multiplizieren (2,6) // => 12 myPrivateMultiplyFunction (2,6) // => ReferenceError: myPrivateMultiplyFunction ist nicht definiert
Die Schließung hat es uns ermöglicht, eine Funktion für den privaten Gebrauch zu definieren, während wir weiterhin kontrollieren können, was der Rest der Welt sieht. Was können Verschlüsse sonst noch??
Verschlüsse sind praktisch, wenn es um die Generierung von Code geht. Sind Sie es leid, sich all diese lästigen Tastencodes für Tastaturereignisse zu merken? Eine übliche Technik ist die Verwendung einer Schlüsselkarte:
var KeyMap = "Enter": 13, "Shift": 16, "Tab": 9, "LeftArrow": 37;
In unserem Tastaturereignis möchten wir dann prüfen, ob eine bestimmte Taste gedrückt wurde:
var txtInput = document.getElementById ('myTextInput'); txtInput.onkeypress = Funktion (e) var code = e.keyCode || e.was wie üblich für den Abruf der gedrückten Taste if (code === KeyMap.Enter) console.log (txtInput.value);
Das obige Beispiel ist nicht das schlechteste, aber wir können Meta-Programmierung und Closures verwenden, um eine noch bessere Lösung zu finden. Mit unserem bestehenden KeyMap
Objekt können wir einige nützliche Funktionen erzeugen:
for (var key in KeyMap) // greift auf ein Objekt mit Array-Zugriff zu, um den Funktionsnamen "dyanamic" zu setzen. KeyMap ["ist" + key] = (function (compare) return function (ev) var code = ev.keyCode | | ev.which; Rückkehrcode === compare;) (KeyMap [key]);
Closures sind so leistungsfähig, weil sie die lokalen Variablen- und Parameterbindungen der Funktion erfassen können, in der sie definiert sind.
Diese Schleife erzeugt ein ist
Funktion für jeden Key in KeyMap
, und unser txtInput.onkeypress
Funktion wird etwas lesbarer:
var txtInput = document.getElementById ('myTextInput'); txtInput.onkeypress = Funktion (e) if (KeyMap.isEnter (e)) console.log (txtInput.value);
Der Zauber beginnt hier:
KeyMap ["ist" + Taste] = (Funktion (vergleiche) ) (KeyMap [Taste]); // sofort aufrufen und den aktuellen Wert an KeyMap [key] übergeben
Wie wir die Tasten einschleifen KeyMap
, Wir übergeben den Wert, auf den dieser Schlüssel verweist, an die anonyme äußere Funktion und rufen ihn sofort auf. Dies bindet diesen Wert an vergleichen Sie
Parameter dieser Funktion.
Die Schließung, an der wir interessiert sind, ist die, aus der anonymen Funktion wir zurückkehren:
return Funktion (ev) var code = ev.keyCode || ev.which; Rückkehrcode === Vergleichen;
Denken Sie daran, dass Funktionen mit dem Gültigkeitsbereich ausgeführt werden, der bei ihrer Definition vorhanden war. Das vergleichen Sie
Parameter ist an den gebunden KeyMap
Wert, der während einer Schleifeniteration vorhanden war, und daher kann unser verschachtelter Abschluss sie erfassen. Wir machen rechtzeitig eine Momentaufnahme des in diesem Moment wirkenden Umfangs.
Die Funktionen, die wir erstellt haben, erlauben es uns, die Einrichtung von zu überspringen Code
Jedes Mal, wenn wir den Schlüsselcode ändern möchten, haben wir jetzt komfortable, lesbare Funktionen.
An diesem Punkt sollte es relativ leicht zu erkennen sein, dass Verschlüsse für das Schreiben von erstklassigem JavaScript unerlässlich sind. Wenden wir das, was wir über Schließungen wissen, an, um einen der nativen Typen von JavaScript zu verbessern (keuchen!). Mit unserem Fokus auf Funktionsobjekte wollen wir das native erweitern Funktion
Art:
Function.prototype.cached = function () var self = this, // "this" bezieht sich auf die ursprüngliche Funktion cache = ; // unsere lokale, lexikalisch gespeicherte Cache-Speicher-Rückgabefunktion (args) if (args in cache) return cache [args]; return cache [args] = self (args); ; ;
Dieses kleine Juwel ermöglicht es jeder Funktion, eine zwischengespeicherte Version von sich selbst zu erstellen. Sie sehen, dass die Funktion selbst eine Funktion zurückgibt, so dass diese Erweiterung wie folgt angewendet und verwendet werden kann:
Math.sin = Math.sin.cached (); Math.sin (1) // => 0.8414709848078965 Math.sin (1) // => 0.8414709848078965 wurde diesmal aus dem Cache gezogen
Beachten Sie die Schließkünste, die ins Spiel kommen. Wir haben einen Einheimischen Zwischenspeicher
Variable, die privat bleibt und von der Außenwelt abgeschirmt ist. Dadurch werden Manipulationen verhindert, die unseren Cache ungültig machen könnten.
Der zurückgegebene Abschluss hat Zugriff auf die äußeren Bindungen der äußeren Funktion. Dies bedeutet, dass wir eine Funktion mit vollem Zugriff auf den Cache im Inneren sowie die ursprüngliche Funktion zurückgeben können! Diese kleine Funktion kann Wunder für die Leistung bewirken. Diese spezielle Erweiterung ist so eingerichtet, dass sie nur ein Argument behandelt. Ich würde mich jedoch sehr freuen, wenn Sie eine Cache-Funktion mit mehreren Argumenten verwenden.
Lassen Sie uns als zusätzlichen Bonus einige Verwendungsmöglichkeiten von Verschlüssen in freier Wildbahn betrachten.
Manchmal die berühmte jQuery $
Factory ist nicht verfügbar (denken Sie an WordPress), und wir möchten es wie üblich verwenden. Anstatt nach zu greifen jQuery.noConflict
, Wir können einen Verschluss verwenden, um Funktionen innerhalb unseres Systems Zugriff zu gewähren $
Parameterbindung.
(function ($) $ (document) .ready (function () // business as usual…);) (jQuery);
Bei großen Backbone.js-Projekten kann es vorteilhaft sein, Ihre Anwendungsmodelle privat zu haben und dann eine öffentliche API in der Hauptanwendungsansicht bereitzustellen. Mit einer Schließung können Sie diese Privatsphäre leicht erreichen.
(Funktion (Export)) var Product = Backbone.Model.extend (urlRoot: '/ products',); var ProductList = Backbone.Collection.extend (url: '/ products', Modell: Product); var Produkte = neue Produktliste; var ShoppingCartView = Backbone.View.extend (addProduct: function (Produkt, Optionen) return CartItems.create (Produkt, Optionen);, removeProduct: Funktion (Produkt, Optionen) Products.remove (Produkt , opts);, getProduct: function (productId) return Products.get (productId);, getProducts: function () return Products.models;); // Export der Hauptanwendungsansicht nur exports.ShoppingCart = neue ShoppingCartView;) (Fenster);
Eine kurze Zusammenfassung des Gelernten:
Vielen Dank fürs Lesen! Fühlen Sie sich frei, um Fragen zu stellen. Nun lasst uns die Pizza-Party genießen!