Ich möchte eine effiziente JavaScript -Klassenbibliothek schreiben, aber ich kann nicht anfangen.
Versuchen Sie, die Bibliothek anderer Menschen zu lesen, aber verstehen Sie sie, als ob es verstanden wird.
Ich habe vor, fortgeschrittene JS -Funktionen gut zu studieren, aber der Inhalt im maßgeblichen Buch ist zu verstreut.
Selbst wenn Sie sich an die "Verwendung" erinnern, denken Sie nicht an die "Methode", wenn Sie "verwenden" möchten.
Vielleicht scheinen Sie wie ich eine unsichtbare Kraft zu haben, die unsere Pläne zurückhält und uns wiederholt denken lässt, dass die Grenzen des Wissens uns still und schwer vorankommen haben.
In dieser Zeit haben sich verschiedene Hausaufgaben, Kursdesign und experimentelle Berichte verdoppelt. Es ist selten, ein wenig Zeit auszudrücken, niemals in den Schlaf zu schlafen und die Bücher auszuräumen, die ich in der Vergangenheit gelesen habe, um näher dem Schreiben meiner eigenen Bibliothek zu sein.
Dieser Artikel wird aus "JavaScript Language Essence" und "Effektives JavaScript" verwiesen. Alle Beispiele wurden debugged. Nachdem ich sie verstanden habe, möchte ich einige "tiefe" Prinzipien ein wenig einfacher machen.
1. variabler Bereich
Zielfernrohr ist für Programmierer wie Sauerstoff. Es ist überall und du denkst nicht einmal darüber nach. Wenn es jedoch verschmutzt ist (z. B. die Verwendung globaler Objekte), werden Sie sich ersticken (z. B. langsame Anwendungsreaktion). JavaScript Core Scope -Regeln sind einfach, sorgfältig gestaltet und sehr leistungsfähig. Eine effektive Verwendung von JavaScript erfordert das Beherrschen einiger grundlegender Konzepte des variablen Umfangs und das Verständnis einiger extremer Situationen, die zu schwer fassbaren, nervigen Problemen führen können.
1.1 Versuchen Sie, so wenig wie möglich globale Variablen zu verwenden
JavaScript ist einfach zu erstellen Variablen in einem globalen Namespace. Das Erstellen globaler Variablen ist mühelos, da keine Erklärung erforderlich ist und von allen Code des gesamten Programms automatisch zugegriffen werden kann.
Bei Anfängern denken wir, wenn wir auf bestimmte Bedürfnisse begegnen (z. Sogar das C-Sprachprozess-orientiertes Denken, das ich in meinem ersten Jahr gelernt habe, ist zu tief verwurzelt, und das System ist ordentlich voller Funktionen. Das Definieren globaler Variablen kann gemeinsamen öffentlichen Namespaces verschmutzen und zu unerwarteten Namenskonflikten führen. Globale Variablen sind auch der Modularität nicht förderlich, da sie eine unnötige Kopplung zwischen unabhängigen Komponenten im Programm verursacht. Ernsthaft sprechen, zu viel global (einschließlich Stilblätter, direkte Definition von Arten von Div oder A) und die Integration in mehreren Menschenentwicklungen ist ein katastrophaler Fehler. Aus diesem Grund ist der gesamte JQuery -Code in einen sofort ausgeführten anonymen Ausdruck eingewickelt - selbst anonyme Funktionen. Wenn der Browser die JQuery -Datei lädt, beginnt die Ausführung unmittelbar nach dem Aufrufen der anonymen Funktion, wobei verschiedene Module von JQuery initialisiert werden, um zu vermeiden, dass globale Variablen zerstört und verschmutzt werden und andere Codes beeinflusst werden.
Die Codekopie lautet wie folgt:
(Funktion (Fenster, undefiniert) {
var jQuery = ...
// ...
window.jQuery = Fenster. $ = jQuery;
})(Fenster);
Darüber hinaus denken Sie vielleicht, dass es bequemer ist, "zu schreiben, wie Sie es zuerst organisieren", aber hervorragende Programmierer werden ständig auf die Struktur des Programms achten, kontinuierlich zusammenhängende Funktionen klassifizieren und irrelevante Komponenten getrennt, und diese Verhaltensweisen sind Teil der Programmierformel.
Da globale Namespaces die einzige Möglichkeit für unabhängige Komponenten in JavaScript -Programmen zur Interaktion sind, ist die Verwendung globaler Benennungskontrollen unvermeidlich. Komponenten oder Bibliotheken müssen einige globale Variablen definieren. Zur Verwendung durch andere Teile des Programms. Andernfalls ist es am besten, lokale Variablen zu verwenden.
Die Codekopie lautet wie folgt:
this.foo; // undefiniert
foo = "global foo";
this.foo; // "global foo"
var foo = "global foo";
this.foo = "verändert";
Foo; // verändert
Der globale Namespace von JavaScript ist auch globaler Objekte ausgesetzt, auf die im globalen Bereich des Programms zugegriffen werden kann und der als Anfangswert dieses Schlüsselworts dient. In einem Webbrowser ist das globale Objekt an die globale Fenstervariable gebunden. Dies bedeutet, dass es zwei Möglichkeiten gibt, eine globale Variable zu erstellen: Deklarieren Sie sie mit VAR im globalen Bereich oder fügen Sie sie dem globalen Objekt hinzu. Der Vorteil der Verwendung von VAR -Deklarationen besteht darin, dass sie die Auswirkungen globaler Variablen im Programmumfang eindeutig ausdrücken können.
Angesichts der Tatsache, dass Verweise auf gebundene globale Variablen zu Laufzeitfehlern führen können, erleichtert klare und prägnante Speicherbereiche den Code -Nutzern, die globalen Variablen zu verstehen, die das Programm deklariert.
Da das globale Objekt einen dynamischen Reaktionsmechanismus für die globale Umgebung bietet, kann es verwendet werden, um eine laufende Umgebung abzufragen und zu erkennen, welche Funktionen auf dieser Plattform verfügbar sind.
EG.ES5 führt ein globales JSON -Objekt vor, um JSON -Formatdaten zu lesen und zu schreiben.
Die Codekopie lautet wie folgt:
if (! this.json) {
this.json = {
analysieren: ..,
Stringify: ...
}
}
Wenn Sie eine Implementierung von JSON anbieten, können Sie natürlich und bedingungslos Ihre eigene Implementierung verwenden. Die integrierten Implementierungen der Hostumgebung sind jedoch nahezu geeignet, da sie in den Browser in C geschrieben werden, da sie nach bestimmten Standards streng nach Genauigkeit und Konsistenz prüfen und im Allgemeinen eine bessere Leistung als Drittanbieter bieten.
Der grundlegende Betrieb der Simulationszeichenfolgen der Datenstrukturkurse erforderte, dass die von der Sprache selbst bereitgestellten Methoden nicht verwendet werden konnten. JavaScript implementiert die grundlegenden Operationen von Arrays sehr gut. Wenn es sich nur um allgemeine Lernbedürfnisse handelt, ist die Idee der von der Sprache selbst bereitgestellten Simulationsmethoden gut. Wenn Sie jedoch wirklich in die Entwicklung investieren, müssen Sie nicht in Betracht ziehen, JavaScript-integrierte Methoden so schnell wie möglich zu verwenden.
1.2 Vermeiden Sie die Verwendung mit mit
Die mit der Erklärung enthält jegliche "Komfort", die Ihre Bewerbung unzuverlässig und ineffizient macht. Wir müssen nacheinander eine Reihe von Methoden auf einem einzelnen Objekt aufrufen. Wenn Sie die mit der Anweisung mit der Anweisung verwenden, können Sie leicht doppelte Verweise auf Objekte vermeiden:
Die Codekopie lautet wie folgt:
Funktionsstatus (info) {
var widget = new Widget ();
mit (widget) {
SetBackground ("blau");
setforenground ("weiß");
setText ("Status:"+info);
zeigen();
}
}
Es ist auch sehr verlockend, die Anweisung mit "importieren" (importieren) Variablen aus einem Modulobjekt zu verwenden.
Die Codekopie lautet wie folgt:
Funktion f (x, y) {
mit (math) {
Return min (Runde (x), SQRT (y)); // abstraktes Zitat
}
}
Tatsächlich behandelt JavaScript alle Variablen gleich. JavaScript beginnt mit dem innersten Bereich und sucht nach außen nach Variablen. Die mit Sprache behandelt ein Objekt, als ob es einen variablen Bereich darstellt. In dem With -Code -Block beginnen die Variablensuche mit der Suche nach Attributen des angegebenen Variablennamens. Wenn die Eigenschaft in diesem Objekt nicht gefunden wird, suchen Sie weiter im externen Bereich. In der Verweise auf jede externe Variable im With -Block wird implizit angenommen, dass es kein Attribut mit demselben Namen im With -Objekt (und eines seiner Prototypobjekte) gibt. Das Erstellen oder Ändern eines Objekts mit oder seinem Prototyp an anderer Stelle im Programm folgt nicht unbedingt solchen Annahmen. Die JavaScript -Engine liest sicherlich keinen lokalen Code, um diese lokalen Variablen zu erhalten, die Sie verwenden. Der JavaScript -Bereich kann als effiziente interne Datenstrukturen dargestellt werden, und die variablen Suche sind sehr schnell. Da jedoch der mit Code -Block mit dem Code -Block nach der Prototyp -Kette des Objekts suchen muss, um alle Variablen im With Code zu finden, ist die Laufgeschwindigkeit viel niedriger als die des allgemeinen Codeblocks.
Anstelle der Sprache ist es einfach, das Objekt an einen kurzen variablen Namen zu binden.
Die Codekopie lautet wie folgt:
Funktionsstatus (info) {
var w = new Widget ();
W.Setbackground ("blau");
W.Setforground ("weiß");
W.SetText ("Status:"+info);
W.Show ();
}
In anderen Fällen besteht der beste Weg, lokale Variablen explizit an relevante Eigenschaften zu binden.
Die Codekopie lautet wie folgt:
Funktion f (x, y) {
var min = math.min,
rund = math.round,
SQRT = Math.sqrt;
return min (rund (x), sqrt (y));
}
1,3 Kenntnis in der Schließung
Es gibt ein einziges Konzept, um Schließungen zu verstehen:
A) Mit JavaScript können Sie Variablen, die außerhalb der aktuellen Funktion definiert sind, Referenzvariablen ermöglichen.
Die Codekopie lautet wie folgt:
Funktion macht und undwich () {
var Magicingredient = "Erdnussbutter";
Funktion make (füllen) {
Return Magicingredient + "und" + Füllung;
}
Rückkehr machen ("Gelee");
}
macht und undwich (); // "Erdnussbutter und Gelee"
b) Selbst wenn die externe Funktion zurückgegeben wurde, kann sich die aktuelle Funktion trotzdem auf die durch die externen Funktion definierte Variable beziehen.
Die Codekopie lautet wie folgt:
Funktion macht und undwich () {
var Magicingredient = "Erdnussbutter";
Funktion make (füllen) {
Return Magicingredient + "und" + Füllung;
}
Rückkehr machen;
}
var f = SandwichMaker ();
f ("Gelee"); // "Erdnussbutter und Gelee"
f ("Bananen"); // "Erdnussbutter und Bananen"
f ("Mallows"); // "Erdnussbutter und Mallows"
Die Funktionswerte von JavaScriptd enthalten mehr Informationen als den Code, der zum Ausführen erforderlich ist, wenn sie aufgerufen werden. Darüber hinaus speichern JavaScript -Funktionswerte auch intern die Variablen, auf die sie sich in ihrem beigefügten Bereich definieren können. Diese Funktionen, die Variablen innerhalb des von ihnen abdeckenden Bereichs verfolgen, werden als Schließungen bezeichnet.
Die Make -Funktion ist ein Verschluss, dessen Code sich auf zwei externe Variablen bezieht: Streitwert und Füllung. Immer wenn die Make -Funktion aufgerufen wird, kann sich der Code auf diese beiden Variablen beziehen, da der Verschluss diese beiden Variablen speichert.
Eine Funktion kann sich auf jede Variable innerhalb ihres Umfangs beziehen, einschließlich Parameter- und externer Funktionsvariablen. Wir können dies verwenden, um allgemeinere SandwichMaker -Funktionen zu schreiben.
Die Codekopie lautet wie folgt:
function macesandwich (magicingRedient) {
Funktion make (füllen) {
Return Magicingredient + "und" + Füllung;
}
Rückkehr machen;
}
var f = SandwichMaker ("Schinken");
f ("Käse"); // "Schinken und Käse"
f ("Senf"); // "Schinken und Senf"
Schließungen sind eines der elegantesten und ausdrucksstärksten Merkmale von JavaScript und auch der Kern vieler Redewendungen.
c) Der Verschluss kann den Wert einer externen Variablen aktualisieren. Tatsächlich speichern Verschlussspeicher auf externe Variablen, nicht auf Kopien ihrer Werte. Daher kann jeder Verschluss mit Zugriff auf diese externen Variablen aktualisiert werden.
Die Codekopie lautet wie folgt:
Funktionsbox () {
var val = undefiniert;
zurückkehren {
SET: Funktion (newval) {val = newval;},
get: function () {return val;},
Typ: function () {return typeof val;}
};
}
var b = box ();
B.Type (); //undefiniert
B.Set (98,6);
B.Get (); // 98.6
B.Type (); // Nummer
Dieses Beispiel erzeugt ein Objekt mit drei Schließungen. Diese drei Schließungen sind festgelegt, tippen und erhalten Eigenschaften, und alle teilen den Zugriff auf VAL -Variablen, und der festgelegte Verschluss aktualisiert den Wert von VAL. Rufen Sie dann GET an und geben Sie die aktualisierten Ergebnisse an.
1.4 Verbesserung der variablen Deklaration verstehen
JavaScript unterstützt diesen Methodenumfang (Verweise auf die variable FOO sind an den Umfang gebunden, das die FOO-Variable am nächsten erklärt), unterstützt jedoch keinen Umfang auf Blockebene (der von der Variablen definierte Bereich ist nicht die engste geschlossene Anweisung oder Code-Block).
Das Nichtverständnis dieser Funktion führt zu einigen subtilen Fehler:
Die Codekopie lautet wie folgt:
Funktion Iswinner (Spieler, andere) {
var höchste = 0;
für (var i = 0, n = Andere.length; i <n; i ++) {
var player = andere [i];
if (Player.Score> höchste) {
höchste = player.score;
}
}
return player.score> höchstes;
}
1.5 Vorsicht vor ungeschickter Umfang der Namensfunktionsausdrücke
Die Codekopie lautet wie folgt:
Funktion double (x) {return x*2; }
var f = Funktion (x) {return x*2; }
Der gleiche Stück Funktionscode kann auch als Ausdruck verwendet werden, weist jedoch völlig unterschiedliche Bedeutungen auf. Der offizielle Unterschied zwischen anonymen Funktionen und benannten Funktionsausdrücken besteht darin, dass letzteres an eine Variable mit demselben Funktionsnamen wie der Funktionsname gebunden ist, der als lokale Variable der Funktion dient. Dies kann verwendet werden, um rekursive Funktionsausdrücke zu schreiben.
Die Codekopie lautet wie folgt:
var f = Funktion find (Baum, Schlüssel) {
// ...
Rückkehr Find (Tree.Left, Schlüssel) ||
find (Baum.Right, Schlüssel);
}
Es ist erwähnenswert, dass der Umfang des Variablen -Fundes nur in seiner eigenen Funktion liegt. Im Gegensatz zu Funktionserklärungen können benannte Funktionsausdrücke nicht extern durch den internen Funktionsnamen referenziert werden.
Die Codekopie lautet wie folgt:
Find (Mytree, "Foo"); // Fehler: Find ist nicht definiert;
var constructor = function () {return null; }
var f = function () {
return constructor ();
};
f (); // {} (in ES3 -Umgebungen)
Das Programm sieht so aus, als würde es Null erzeugen, aber tatsächlich ein neues Objekt erzeugt.
Da die benannte Funktionsvariable Object.Prototype.Constructor (d. H. Der Konstruktor von Oject) erbringt, wird dieser Bereich durch die dynamischen Änderungen des Objekts.Prototyps beeinflusst. Der Weg, um zu vermeiden, dass Objekte den Funktionsumfang der Funktionsausdrücke im System kontaminieren, besteht darin, zu jeder Zeit zu vermeiden, dass Eigenschaften im Objekt hinzugefügt werden.
Ein weiterer Nachteil in der beliebten JavaScript -Engine ist die Förderung der Erklärung benannter Funktionsausdrücke.
Die Codekopie lautet wie folgt:
var f = Funktion g () {return 17;}
G(); // 17 (in der Nichtkonformatumgebung)
Einige JavaScript -Umgebungen verwenden sogar die beiden Funktionen F und G als unterschiedliche Objekte, was zu einer unnötigen Speicherzuweisung führt.
1.6 Vorsicht vor ungeschickter Bereich für lokale Blockfunktionen
Die Codekopie lautet wie folgt:
Funktion f () {return "global"; }
Funktionstest (x) {
Funktion f () {return "local";}
var result = [];
if (x) {
result.push (f ());
}
result.push (f ());
Ergebnisergebnis;
}
Test (wahr); // ["lokal", "lokal"]
test (falsch); // ["Lokal"]
Die Codekopie lautet wie folgt:
Funktion f () {return "global"; }
Funktionstest (x) {
var result = [];
if (x) {
Funktion f () {return "local";}
result.push (f ());
}
result.push (f ());
Ergebnisergebnis;
}
Test (wahr); // ["lokal", "lokal"]
test (falsch); // ["Lokal"]
JavaScript hat keinen Umfang auf Blockebene, daher sollte der Umfang der internen Funktion F die gesamte Testfunktion sein. Einige JavaScript -Umgebungen, aber nicht alle JavaScript -Umgebungen. JavaScript-Implementierungen berichten von Funktionen wie Fehler im Striktmodus (Programme im strengen Modus mit lokalen Blockfunktionserklärungen werden als Syntaxfehler melden), mit denen nicht portable Code erfasst werden kann, wodurch die Deklarationen der lokalen Blockfunktion für zukünftige Standardversionen mehr und mögliche Semantik verleiht. In diesem Fall ist es möglich, eine lokale Variable innerhalb der Testfunktion zu deklarieren, um auf die globale Funktion F zu verweisen.