Vertieftes Verständnis davon in JavaScript

Vertieftes Verständnis davon in JavaScript

Vertieftes Verständnis davon in Js

JavaScript Bereich ist static scope Bereich, aber this ist in Js eine Ausnahme. Das this ist ähnlich wie beim dynamischen Bereich. Es ist egal, wie und wo Funktionen und Bereiche deklariert werden, sondern nur, von wo aus sie aufgerufen werden. Der this kann nicht bestimmt werden, wenn die Funktion definiert wird. Erst wenn die Funktion ausgeführt wird, kann bestimmt werden, auf wen this tatsächlich zeigt. Tatsächlich zeigt this natürlich letztendlich auf das Objekt, das es aufruft.

Umfang

Lassen Sie uns zunächst den Gültigkeitsbereich von JavaScript verstehen, um zu verstehen, warum this eher einem dynamischen Gültigkeitsbereich ähnelt. Im Allgemeinen sind die in einem Programmcode verwendeten Namen nicht immer gültig oder verfügbar, und der Gültigkeitsbereich des Codes, der die Verfügbarkeit dieses Namens einschränkt, ist der scope dieses Namens. Wenn eine Methode oder ein Mitglied deklariert wird, hat es den aktuellen context . Im context mit einem bestimmten Wert ist der Ausdruck sichtbar und kann referenziert werden. Wenn sich eine Variable oder ein anderer Ausdruck nicht im aktuellen Gültigkeitsbereich befindet, ist er nicht verfügbar. Bereiche können auch hierarchisch sein, sodass untergeordnete Bereiche auf übergeordnete Bereiche zugreifen können (normalerweise durch Befolgen einer Bereichskette). Auf Variablen und Referenzen in untergeordneten Bereichen kann jedoch nicht von übergeordneten Bereichen aus verwiesen werden.
Der Gültigkeitsbereich JavaScript ist static scope , der auch als lexical scope Gültigkeitsbereich bezeichnet werden kann. Seine Hauptfunktion besteht darin, dass ein Funktionsbereich, wenn er auf eine lokale Variable stößt, die weder ein Parameter ist noch innerhalb einer Funktion definiert ist, im Kontext der Funktionsdefinition sucht. Im Gegensatz dazu ist dynamic scope anders. Wenn ein Funktionsbereich auf eine lokale Variable stößt, die weder ein Parameter ist noch innerhalb einer Funktion definiert ist, sucht er im Kontext des Funktionsaufrufs.

var a = 1;
var s = Funktion(){
 konsole.log(a);
};
(Funktion(){
 var a = 2;
 s(); // 1
})();

Wenn s() aufgerufen wird, wird a als 1 ausgegeben. Dies ist ein statischer Bereich, d. h. der Bereich wird bei der Deklaration angegeben. Wenn es ein dynamischer Bereich ist, wird hier 2 ausgegeben. Die meisten Sprachen verwenden heute einen statischen Gültigkeitsbereich, beispielsweise C , C++ , Java , PHP , Python usw. Zu den Sprachen mit dynamischem Gültigkeitsbereich gehören Emacs Lisp , Common Lisp , Perl usw.

Globaler Umfang

Direkt auf der obersten Ebene deklarierte Variablen oder Methoden werden im globalen Gültigkeitsbereich ausgeführt. Verwenden Sie die Eigenschaft [[Scopes]] der Funktion, um den Gültigkeitsbereich anzuzeigen. [[Scopes]] ist ein Objekt, das die Gültigkeitsbereichskette der Funktion speichert. Es handelt sich um eine interne Eigenschaft der Funktion, auf die nicht direkt zugegriffen werden kann, die aber zum Anzeigen ausgedruckt werden kann.

Funktion s(){}
Konsole.Dir(s);
/*
 ...
 [[Bereiche]]: Bereiche[1]
 0: Global ...
*/
// Sie können sehen, dass die deklarierte s-Funktion im globalen Bereich ausgeführt wird.

Funktionsumfang

Wenn eine Funktion deklariert wird, ist die Betriebsumgebung der innerhalb der Funktion deklarierten Methoden oder Mitglieder der Funktionsumfang der Funktion.

(Funktion lokalerKontext(){
 var a = 1;
 Funktion s(){ return a; }
 Konsole.Dir(s);
})();
/*
 ...
 [[Bereiche]]: Bereiche[2]
 0: Abschluss (lokaler Kontext) {a: 1}
 1: Global ...
*/
// Sie können sehen, dass der Kontext, in dem die deklarierte s-Funktion ausgeführt wird, der Bereich der Funktion localContext ist, der auch als lokaler Bereich bezeichnet werden kann

Blockbereich

Wenn in einem Codeblock let oder const vorhanden ist, bildet der Codeblock einen geschlossenen Bereich für die von diesen Befehlen vom Anfang des Blocks an deklarierten Variablen.

{
 sei a = 1;
 Funktion s(){Rückgabe a;}
 Konsole.Dir(s);
 /*
 ...
 [[Bereiche]]: Bereiche[2]
 0: Blockieren {a: 1}
 1: Global ...
 */
}
// Sie können sehen, dass die deklarierte s-Funktion im Blockbereich ausgeführt wird, der auch der lokale Bereich ist.

analysieren

Bevor wir this müssen wir verstehen, warum this in JavaScript entwickelt wurde. Lassen Sie uns vorher ein kleines Beispiel nehmen. Normalerweise ähnelt das typische Problem, auf das wir bei der Verwendung stoßen können, dem this . Obwohl wir dieselbe Funktion ausführen, können die Ausführungsergebnisse unterschiedlich sein.

var obj = {
 Name: 1,
 sagen Sie: function() {
 gib diesen Namen zurück;
 }
};
Fenster.name = 2;
Fenster.sagen = Objekt.sagen;

konsole.log(obj.say()); // 1
konsole.log(fenster.say()); // 2

Der Grund für dieses Ergebnis ist die Verwendung des Schlüsselworts this . Wie bereits erwähnt, muss this zur Laufzeit bestimmt werden. Hier ist für obj.say() die Umgebung, in der say() ausgeführt wird, obj , und für window.say() ist die Umgebung, in der say() ausgeführt wird, das Objekt window . Daher sind die Ergebnisse der beiden Vorgänge unterschiedlich.
Lassen Sie uns nun verstehen, warum JavaScript ein solches this hat. Lassen Sie uns zunächst den Stapel in der Speicherstruktur von JavaScript verstehen. Der heap ist dynamisch zugewiesener Speicher mit einer unbestimmten Größe und wird nicht automatisch freigegeben. Dem stack wird automatisch Speicherplatz zugewiesen und er wird während der Codeausführung automatisch freigegeben. JavaScript bietet eine Umgebung für die Ausführung Js -Code im Stapelspeicher. Alle Bereichs- und Funktionsaufrufe werden im Stapelspeicher ausgeführt. Die grundlegenden Datentypen in Js , String , Number , Boolean , Null , Undefined und Symbol , belegen wenig Platz und haben eine feste Größe. Die Werte werden direkt im Stapelspeicher gespeichert und der Zugriff erfolgt über den Wert. Beim Object wird sein Zeiger im Stapelspeicher abgelegt, zeigt auf die tatsächliche Adresse des Heapspeichers und der Zugriff erfolgt über die Referenz.
Sehen wir uns nun das obige Beispiel an. Im Speicher wird das Objekt obj im Heap-Speicher gespeichert. Wenn der Attributwert im Objekt ein Basisdatentyp ist, wird er im selben Speicherbereich wie das Objekt gespeichert. Dieser Attributwert kann jedoch auch ein Referenztyp sein, sodass die Funktion say auch im Heap-Speicher vorhanden ist. Tatsächlich können wir dies hier so verstehen, dass sich die tatsächliche Definition dieser Funktion in einem Speicherbereich befindet (der in Form einer anonymen Funktion vorhanden ist) und sich das Objekt obj auch in einem anderen Speicherbereich befindet. obj zeigt über say auf die Speicheradresse dieser anonymen Funktion, obj --say--> funtion , und jetzt kommt das Problem. Aufgrund dieser Speicherstruktur können wir jedes variable Objekt auf diese Funktion zeigen lassen. In JavaScript Funktionen muss es uns daher gestattet sein, den Wert der Ausführungsumgebung abzurufen, um ihn verwenden zu können. Wir müssen über einen Mechanismus verfügen, um den aktuellen context innerhalb des Funktionskörpers abzurufen, damit this angezeigt wird. Sein Designzweck besteht darin, innerhalb des Funktionskörpers auf die aktuelle Ausführungsumgebung der Funktion zu verweisen.

verwenden

Wir müssen bedenken, dass this zur Laufzeit gebunden wird, nicht zur Definitionszeit. Sein context hängt von verschiedenen Bedingungen ab, wenn die Funktion aufgerufen wird. Einfach ausgedrückt hat die Bindung von this nichts mit dem Ort der Funktionsdeklaration zu tun, sondern hängt nur davon ab, wie die Funktion aufgerufen wird. Einfach ausgedrückt zeigt this immer auf den Aufrufer, mit Ausnahme von Pfeilfunktionen. Als Nächstes stellen wir fünf Verwendungsmöglichkeiten von this vor.

Standardbindung

Der am häufigsten verwendete Funktionsaufruftyp ist der unabhängige Funktionsaufruf, der auch die niedrigste Priorität hat. this zeigt derzeit auf das globale Objekt. Beachten Sie, dass das globale Objekt bei Verwendung strict mode die Standardbindung nicht verwenden kann, sodass this zu undefined wird.

var a = 1; // Variablendeklaration in der globalen Objektfunktion f1() {
 gib dies.a zurück;
}

Funktion f2() {
 "streng verwenden";
 gib dies zurück;
}

console.log(f1()); // 1 // Ruft tatsächlich window.f1() auf und dies zeigt immer auf den Anrufer, also window
console.log(f2()); // undefiniert // Tatsächlich wird window.f2() aufgerufen. Zu diesem Zeitpunkt ist dies innerhalb der Funktion undefiniert, da der strikte Modus „strict“ verwendet.

Implizite Bindung

Nur die oberste oder letzte Ebene in der Objekt-Eigenschaftsreferenzkette wird this betroffen sein. Ebenso zeigt this immer auf den Anrufer. Insbesondere sollte es auf den aktuellsten Anrufer zeigen, mit Ausnahme von Pfeilfunktionen. Darüber hinaus können wir absichtlich oder unabsichtlich indirekte Referenzen erstellen. In diesem Fall gilt this auch für den Anrufer. Das in der obigen Analyse verwendete Beispiel gehört zum Fall der indirekten Referenz.

Funktion f() {
 konsole.log(dies.a);
}
var obj1 = {
 ein: 1,
 f: f
};
var obj2 = {
 eine: 11,
 obj1: obj1
};
obj2.obj1.f(); // 1 // Die letzte Ebene der Anrufer ist obj1
Funktion f() {
 konsole.log(dies.a);
}
var obj1 = {
 ein: 1,
 f: f
};
var obj2 = {
 eine: 11,
};
obj2.f = obj1.f; // indirekte Referenz obj2.f(); // 11 // der Anrufer ist obj2

Bindung anzeigen

Wenn wir eine Funktion in eine bestimmte Umgebung zwingen möchten, also ein Objekt, können wir apply apply() , call und bind verwenden, um this zur Ausführung zu binden. Jedes Function hat die Methoden „apple()“, „ call() und bind() , die die Funktion in einem bestimmten Bereich aufrufen können, was dem Setzen des Werts this im Funktionskörper entspricht, um den Bereich zu erweitern, in dem die Funktion ausgeführt wird. Darüber hinaus ist zu beachten, dass die Verwendung von bind zum Binden von this eine höhere Priorität hat als apply “ und call , d. h. nachdem „ bind zum Binden von „ this verwendet wurde, kann die Verwendung von „ apply und call den Sinn von this nicht mehr ändern.

window.name = "A"; // Name, der dem Fensterobjekt zugeordnet ist
document.name = "B"; // Name, der dem Dokumentobjekt zugeordnet ist
var s = { // Ein Objekt anpassen s
 Name: "C"
}

var rollCall = {
 Name: "Lehrer",
 sageName: function(){
 konsole.log(dieser.name);
 }
}
rollCall.sayName(); // Lehrer

// anwenden
rollCall.sayName.apply(); // A // Es werden keine Parameter übergeben und das Standardfenster ist gebunden
rollCall.sayName.apply(window); // A // Fensterobjekt binden rollCall.sayName.apply(document); // B // Dokumentobjekt binden rollCall.sayName.apply(s); // C // Benutzerdefiniertes Objekt binden // call
rollCall.sayName.call(); // A // Es werden keine Parameter übergeben und das Standardfenster ist gebunden
rollCall.sayName.call(window); // A // An Fensterobjekt binden rollCall.sayName.call(document); // B // An Dokumentobjekt binden rollCall.sayName.call(s); // C // An benutzerdefiniertes Objekt binden // binden // Das letzte () dient zur Ausführung rollCall.sayName.bind()(); //A // Standardbindung an Fenster ohne Übergabe von Parametern
rollCall.sayName.bind(window)(); //A // Fensterobjekt binden rollCall.sayName.bind(document)(); //B // Dokumentobjekt binden rollCall.sayName.bind(s)(); // C // Benutzerdefiniertes Objekt binden

Neue Bindung

In JavaScript ist new eine Syntaxvereinfachung, die das Schreiben von Code vereinfacht und Objektinstanzen stapelweise erstellen kann. Die folgenden Vorgänge werden tatsächlich im new -Prozess ausgeführt.

Erstellt ein leeres, einfaches JavaScript Objekt, d. h. {} . Verknüpft dieses Objekt (d. h. legt den Konstruktor des Objekts fest) mit einem anderen Objekt. Verwenden Sie das in Schritt 1 erstellte Objekt als context this . Wenn die Funktion kein Objekt zurückgibt, wird das in Schritt 1 erstellte Objekt zurückgegeben.

Funktion _new(Basis,...Argumente){
 var obj = {};
 obj.__proto__ = Basis.Prototyp;
 Basis.anwenden(Objekt, Argumente);
 gibt Objekt zurück;
}

Funktion Funct(a) {
 dies.a = a;
}
var f1 = neue Funktion(1);
konsole.log(f1.a); // 1

var f2 = _new(Funktion, 1);
konsole.log(f2.a); // 1

Pfeilfunktionen

Pfeilfunktionen haben kein separates this . Wenn this im Hauptteil einer Pfeilfunktion verwendet wird, wird this in der context abgerufen. Wenn eine Pfeilfunktion aufgerufen wird, generiert sie this nicht in ihrem eigenen Bereich. Sie erbt this nur von der vorherigen Ebene ihrer Bereichskette. Da die Pfeilfunktion keinen eigenen this -Zeiger besitzt, können mit apply , call und bind nur Parameter übergeben, this -Zeiger der Pfeilfunktion jedoch nicht dynamisch geändert werden. Darüber hinaus kann die Pfeilfunktion nicht als Konstruktor verwendet werden und bei der Instanziierung mit new wird eine Exception ausgelöst.

Fenster.name = 1;
var obj = {
 Name: 11,
 sagen Sie: function(){
 const f1 = () => {
 gib diesen Namen zurück;
 }
 console.log(f1()); // 11 // Der direkte Aufrufer ist window, aber da die Pfeilfunktion this nicht bindet, wird this im Kontext erhalten, also das obj-Objekt const f2 = function(){
 gib diesen Namen zurück;
 }
 console.log(f2()); // 1 // Der direkte Aufrufer ist window, eine normale Funktion, also returniere this.name;
 }
}

console.log(obj.say()); // 11 // Der direkte Aufrufer ist obj. Das this des Kontexts in der Funktion während der Ausführung ist das obj-Objekt

Beispiel

Funktion s(){
 konsole.log(dies);
}

// Direkt im Fenster aufrufen // Nicht strikt verwenden
s(); // Fenster // Entspricht window.s(), der Aufrufer ist window
// Fenster ist eine Instanz von Fenster // Fensterinstanz von Fenster //true

// Erstelle ein neues Objekt s1
var s1 = {
 t1: function(){ // Testen Sie, ob dies auf den Anrufer verweist console.log(this); // s1
 s(); // Window // Dieser Aufruf ist immer noch äquivalent zu window.s(), der Aufrufer ist window
 },
 t2: () => { // Pfeilfunktion testen, diese zeigt nicht auf den Anrufer console.log(this);
 },
 t3: { // Objekt im Testobjekt tt1: function() {
 konsole.log(dies);
 } 
 },
 t4: { // Teste die Pfeilfunktion und den Nicht-Funktionsaufruf. Dieser zeigt nicht auf den Anrufer tt1: () => {
 konsole.log(dies);
 } 
 },
 t5: function(){ // Beim Testen eines Funktionsaufrufs zeigt der Pfeil dieser Funktion auf den Aufrufer des vorherigen Objekts. return {
 tt1: () => {
 konsole.log(dies);
 }
 }
 }
}
s1.t1(); // s1-Objekt // Der Aufrufer hier ist s1, also ist das gedruckte Objekt s1
s1.t2(); // Fenster
s1.t3.tt1(); // s1.t3 Objekt s1.t4.tt1(); // Fenster
s1.t5().tt1(); // s1-Objekt

Dies ist das Ende dieses Artikels über ein vertieftes Verständnis von this in Js. Weitere relevante Inhalte zum vertieften Verständnis von this in Js finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • Ausführungsumgebung und Gültigkeitsbereichskette in JavaScript
  • Detaillierte Erklärung der Verwendung von JavaScript-Bereich, Bereichskette und Abschluss
  • Das Konzept und die Verwendung der Bereichskette in JavaScript
  • Eine kurze Einführung in den JavaScript-Bereich
  • Ein tiefer Einblick in den lexikalischen Geltungsbereich von JavaScript
  • Detaillierte Erklärung der JavaScript-Bereichsschließung
  • Analyse des Umfangs und des Variablenbereichs in JS

<<:  Über MySQL innodb_autoinc_lock_mode

>>:  Ausführliche Erklärung der Umgebungsvariablen und Konfigurationsdateien in CentOS

Artikel empfehlen

Schritte zur VMware-Konfiguration des VMnet8-Netzwerks

Inhaltsverzeichnis 1. Einleitung 2. Konfiguration...

So installieren und verwenden Sie Cockpit unter CentOS 8/RHEL 8

Cockpit ist ein webbasiertes Serververwaltungstoo...

CSS3 zum Erreichen eines Menü-Hover-Effekts

Ergebnis: html <nav id="nav-1"> &...

Eine benutzerfreundliche Alternative in Linux (Befehl fd)

Der Befehl fd bietet eine einfache und unkomplizi...

Drei Möglichkeiten zum Implementieren eines Textfarbverlaufs in CSS

Bei der Entwicklung von Web-Frontends entwerfen U...

So stellen Sie per SSH eine Verbindung zum Docker-Server her

Als ich zum ersten Mal mit Docker in Berührung ka...

Tutorial zur Installation von MySQL 5.7.18 mit einem RPM-Paket

System: CentOS 7 RPM-Pakete: mysql-community-clie...

So fügen Sie Tastenkombinationen in Xshell hinzu

Als nützlicher Terminalemulator wird Xshell häufi...

Lösung für die Navicat Premier-Remoteverbindung zum MySQL-Fehler 10038

Schlägt die Remote-Verbindung zu MySQL fehl, kann...

Sehr detaillierte Anleitung zum Upgrade der MySQL-Version

Inhaltsverzeichnis 1. Einleitung 2. Sichern Sie d...

So verwenden Sie Webpack und Rollup zum Verpacken von Komponentenbibliotheken

Vorwort Ich habe zuvor eine Komponente im Ladesti...

Vier Möglichkeiten zum Vergleichen von JavaScript-Objekten

Inhaltsverzeichnis Vorwort Referenzvergleich Manu...

So verwenden Sie mysqldump zum Sichern von MySQL-Daten

1. Einführung in mysqldump mysqldump ist ein logi...