Tipp
Zunächst weiß ich, dass dieser Artikel langweilig ist, er ist in JS nichts weiter als das, und es gab Tausende von Artikeln, die diesen Teil geschrieben haben.
Ich möchte jedoch immer noch einen Artikel darüber in JS schreiben, der als Zusammenfassung angesehen werden kann. (Götter können herumgehen und meine anderen Artikel lesen)
In JS ist der Kontext immer unvorhersehbar, und oft sind Fehler immer verwirrt. Solange Sie deutlich unterscheiden, wie man unter verschiedenen Umständen ausgeführt wird, wird es in Ordnung sein.
Globale Ausführung
Schauen wir uns zunächst an, was dies in der globalen Umgebung ist:
Erste. Browser:
console.log (this); // Fenster {Sprachsynthesis: Sprachsynthese, Caches: Cachestorage, Localstorage: Speicher, SessionStorage: Speicher, WebkitStorageInfo: depressive StorageInfo…}Sie können sehen, dass das Fensterobjekt gedruckt ist.
zweite. Knoten:
console.log (this); // global
Sie können sehen, dass das globale Objekt gedruckt ist.
Zusammenfassung: Im globalen Bereich führt dies das aktuelle globale Objekt aus (Fenster im Browser, global im Knoten).
In der Funktion ausführen
Reine Funktionsaufrufe
Dies ist die häufigste Art, die Funktion zu verwenden:
Funktion test () {console.log (this);}; test (); // Fenster {Sprachsynthesis: Sprachsynthesis, Caches: Cachestorage, LocalStorage: Speicher, SessionStorage: Speicher, WebkitStorageInfo: deprescatedStorageInfo…}…}…}.Wir können sehen, dass eine Funktion, die direkt aufgerufen wird, zu einem globalen Aufruf gehört und zu diesem Zeitpunkt dies auf das globale Objekt hinweist.
Strikter Modus 'Strikte';
Wenn reine Funktionsaufrufe im strengen Modus ausgeführt werden, weist dies hier nicht auf die globale, sondern nicht definiert. Dies soll ein unregeliges Verhalten in JS beseitigen:
'strict'; function test () {console.log (this);}; test (); // undefiniertNatürlich wäre es besser, es in eine sofortige Ausführungsfunktion zu setzen und die globale Situation zu vermeiden:
(function () {"strikt verwenden"; console.log (this);}) (); // undefiniertMethodenaufruf als Objekt
Wenn eine Funktion als Objektmethode aufgerufen wird:
var obj = {name: 'qiutc', foo: function () {console.log (this.name); }} obj.foo (); // 'qiutc'Zu diesem Zeitpunkt weist dies auf das aktuelle Objekt hin;
Natürlich können wir das tun:
Funktion test () {console.log (this.name);} var obj = {name: 'qiutc', foo: test} obj.foo (); // 'qiutc' 'Auch unverändert, da in JS alles ein Objekt ist und eine Funktion auch ein Objekt ist. Für den Test handelt es sich nur um einen Funktionsnamen, ein Verweis auf die Funktion, die auf diese Funktion hinweist. Wenn foo = testen, weist Foo auch auf diese Funktion hin.
Was ist, wenn Sie die Methode des Objekts einer Variablen zuweisen und diese Variable direkt aufrufen:
var obj = {name: 'qiutc', foo: function () {console.log (this); }} var test = obj.foo; test (); // FensterEs ist zu sehen, dass dies zu dieser Zeit die globale Welt ausführt. Wenn wir test = obj.foo platzieren, testen Sie direkt auf einen Verweis auf eine Funktion. Zu diesem Zeitpunkt hat es tatsächlich nichts mit dem OBJ -Objekt zu tun, so dass es direkt als gewöhnliche Funktion bezeichnet wird, sodass dies auf das globale Objekt weist.
Einige Fallstricke
Wir stoßen oft auf einige Fallstricke in Rückruffunktionen:
var obj = {name: 'qiutc', foo: function () {console.log (this); }, foo2: function () {console.log (this); setTimeout (this.foo, 1000); }} obj.foo2 ();Nachdem wir diesen Code ausgeführt haben, werden wir feststellen, dass sich die Ausdrucke voneinander unterscheiden:
Das erste Mal besteht darin, dies direkt in Foo2 zu drucken, was hier auf das OBJ -Objekt hinweist, wir haben keine Zweifel;
Dies.Foo wird jedoch in SetTimeout auf das globale Objekt ausgeführt. Wird es hier nicht als Funktionsmethode verwendet? Dies verwirrt viele Anfänger;
Tatsächlich ist SetTimeOut nur eine Funktion, und die Funktion benötigt möglicherweise Parameter. Wir übergeben dies als Parameter an die SetTimeout -Funktion, genau wie es einen unterhaltsamen Parameter erfordert. Beim Passieren des Parameters haben wir tatsächlich einen solchen Operation Fun = this.foo gemacht. Wenn wir sehen, dass es keine gibt, zeigen wir direkt Spaß auf die Referenz dieses. Bei der Ausführung wird Fun () tatsächlich ausgeführt, so dass es nichts mit OBJ zu tun hat. Es wird direkt als gewöhnliche Funktion bezeichnet, sodass dies auf das globale Objekt zeigt.
Dieses Problem tritt häufig in vielen asynchronen Rückruffunktionen auf.
lösen
Um dieses Problem zu lösen, können wir die Schließfunktion verwenden, um damit umzugehen:
var obj = {name: 'qiutc', foo: function () {console.log (this); }, foo2: function () {console.log (this); var _this = this; setTimeout (function () {console.log (this); // window console.log (_this); // Objekt {Name: "qiutc"}}, 1000); }} obj.foo2 ();Sie können sehen, dass das direkte Verwenden dieses Fensters immer noch ein Fenster ist. Da dies in Foo2 auf OBJ verweist, können wir zuerst eine Variable verwenden, um sie zu speichern und dann in der Rückruffunktion auf das aktuelle Objekt zu verweisen.
Eine weitere Grube der SetTimeout
Wie bereits erwähnt, ist dies der Punkt auf das globale Objekt (Fenster), das im strengen Modus direkt ohne Bindungsumfang ausgeführt wird. Die Rückruffunktion in SetTimeOut zeigt jedoch im strengen Modus unterschiedlich:
'Verwenden Sie Strict'; Funktion foo () {console.log (this);} setTimeout (foo, 1); // FensterLogischerweise haben wir den strengen Modus hinzugefügt, und der FOO -Aufruf hat dies nicht angegeben, daher sollte er undefiniert sein, aber hier gibt es immer noch ein globales Objekt. Liegt es daran, dass der strenge Modus fehlgeschlagen ist?
Nein, selbst im strengen Modus, wenn die SetTimeout -Methode die eingehende Funktion aufruft, wird der globale Kontext automatisch injiziert, wenn die Funktion dies nicht angibt, was dem Aufrufen von Foo.apply (Fenster) anstelle von Foo () entspricht.
Wenn wir dies bei der Übergabe der Funktion bereits angeben, werden wir natürlich nicht in das globale Objekt injiziert, wie z. B. SetTimeout (Foo.bind (OBJ), 1) ;;
Als Konstruktor verwenden
In JS müssen wir einige Konstrukteure definieren, und das Keyword -Neue muss beim Aufrufen eines Konstruktors hinzugefügt werden: Das Keyword muss hinzugefügt werden:
Funktionsperson (Name) {this.name = name; console.log (this);} var p = new Person ('qiutc'); // Person {Name: "qiutc"}Wir können sehen, dass dies, wenn sie als Konstruktor aufgerufen wird, dies auf das Objekt verweist, das so instanziiert ist, dass dieser Konstruktor aufgerufen wird.
Natürlich ist der Konstruktor tatsächlich eine Funktion. Wenn wir es als normale Funktion ausführen, wird dies dennoch global ausgeführt:
Funktionsperson (Name) {this.name = name; console.log (this);} var p = person ('qiutc'); // FensterDer Unterschied besteht darin, die Funktion aufzurufen (neu).
Pfeilfunktion
In der neuen ES6 -Spezifikation wurde eine Pfeilfunktion hinzugefügt. Das unterschiedlichste von gewöhnliche Funktionen ist dieser Zeig, der zeigte. Erinnerst du dich, dass wir Schließungen verwenden, um dieses Zeigeproblem zu lösen? Wenn wir die Pfeilfunktion verwenden, können wir sie perfekter lösen:
var obj = {name: 'qiutc', foo: function () {console.log (this); }, foo2: function () {console.log (this); setTimeout (() => {console.log (this); // Objekt {Name: "qiutc"}}, 1000); }} obj.foo2 ();Wie Sie sehen können, hätte sie in der von SetTimeOut ausgeführten Funktion im Fenster ausgedruckt werden müssen, aber dies zeigt hier auf OBJ. Der Grund dafür ist, dass die an SetTimeout übergebene Funktion (Parameter) eine Pfeilfunktion ist:
Dieses Objekt in der Funktionskörper ist das definierte Objekt, nicht das verwendete Objekt.
Basierend auf Beispielen verstehen wir diesen Satz:
Wenn obj.foo2 () ausgeführt wird, ist der Strom, der dies auf OBJ zeigt; Bei der Ausführung von SetTimeout definieren wir zunächst eine anonyme Pfeilfunktion, und der Schlüsselpunkt ist hier. Das Objekt in der Pfeilfunktion, in dem diese bei der Definition dieser Pfeilfunktion ausgeführt wird, wird in Umfang auf diesen Bereich hingewiesen, wenn diese Pfeilfunktion definiert wird, dh in obj.foo2, dh OBJ; Wenn Sie also die Pfeilfunktion ausführen, ist dies -> obj in obj.foo2 -> obj;
Einfach ausgedrückt, dies in der Pfeilfunktion hängt nur im Bereich des Geltungsbereichs zusammen und hat nichts damit zu tun, wo und wie es genannt wird. Gleichzeitig ist dies unveränderlich.
Rufen Sie an, bewerben Sie sich, binden Sie
In JS sind Funktionen auch Objekte, und es gibt auch einige Methoden. Hier führen wir drei Methoden ein, sie können diesen Zeiger in der Funktion ändern:
Anruf
fun.call (thisArg [, arg1 [, arg2 [, ...]]])
Es wird die Funktion sofort ausführen. Der erste Parameter gibt den Kontext in der Ausführungsfunktion an, und der nachfolgende Parameter sind die Parameter, die in der Ausführungsfunktion übergeben werden müssen.
anwenden
fun.apply (thisArg [, [arg1, arg2, ...]])
Es wird die Funktion sofort ausführen. Der erste Parameter gibt den Kontext dieser in der Ausführungsfunktion an, und der zweite Parameter ist ein Array, das der an die Ausführungsfunktion übergebene Parameter (die Differenz vom Anruf) ist;
binden
var foo = fun.bind (thisarg [, arg1 [, arg2 [, ...]]]);
Es wird die Funktion nicht ausgeführt, sondern gibt eine neue Funktion zurück. Diese neue Funktion gibt den Kontext an, und die nachfolgenden Parameter sind die Parameter, die übergeben werden müssen, um die Funktion auszuführen.
Diese drei Funktionen sind tatsächlich ähnlich. Der Gesamtzweck besteht darin, den Kontext einer Funktion anzugeben (dies). Nehmen wir die Anruffunktion als Beispiel.
Geben Sie dies für eine normale Funktion an
var obj = {name: 'qiutc'}; Funktion foo () {console.log (this);} foo.call (obj); // Objekt {Name: "qiutc"}Es ist ersichtlich, dass bei der Ausführung von Foo.call (OBJ) dies in der Funktion auf das OBJ -Objekt zeigt, das erfolgreich ist;
Geben Sie eine dies für die Methode im Objekt an
var obj = {name: 'qiutc', foo: function () {console.log (this); }} var obj2 = {name: 'tcqiu222222'}; obj.foo.call (obj2); // Objekt {Name: "Tcqiu222222"}Sie können sehen, dass dies bei der Ausführung der Funktion auf OBJ2 hinweist, was erfolgreich ist.
Geben Sie dies für den Konstruktor an
Funktionsperson (Name) {this.name = name; console.log (this);} var obj = {name: 'qiutc2222222'}; var p = new Person.call (obj, 'qiutc'); // Unbefundt TypeError: Person.Call ist kein Konstruktor (…)Hier wurde ein Fehler gemeldet, weil wir zur neuen Person gegangen sind. Call -Funktion, keine Person, und die Funktion hier ist kein Konstruktor.
Ändern, um zu binden und zu versuchen:
Funktionsperson (Name) {this.name = name; console.log (this);} var obj = {name: 'qiutc2222222'}; var person2 = person.bind (obj); var p = new Person2 ('qiutc'); // person {name: "qiutc"} console.log (obj); // Object {name: "qiutc22222222222222222222222222222222222222222222222222222222222222222222222.Was gedruckt wird, ist das von der Person instanziierte Objekt, das nichts mit OBJ zu tun hat, und OBJ hat sich nicht geändert, was darauf hinweist, dass wir diesen Kontext für Person ohne Wirkung angeben.
Daher kann der Schluss gezogen werden, dass die Verwendung von BIND, um dies für einen Konstruktor anzugeben. Wenn ein neuer Konstruktor durch die Bindfunktion angegeben wird, wirkt sich dies nicht aus.
Natürlich kann Bind dies nicht nur angeben, sondern auch Parameter übergeben. Versuchen wir diese Operation:
Funktionsperson (Name) {this.name = name; console.log (this);} var obj = {name: 'qiutc2222222'}; var person2 = person.bind (obj, 'qiutc1111'); var p = new Person2 ('qiutc'); // person {name: "qiutc111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111RWie Sie sehen können, funktionieren die eingehenden Parameter, obwohl die Angabe dieses nicht funktioniert, immer noch.
Geben Sie dies für die Pfeilfunktion an
Definieren wir eine Pfeilfunktion unter der globalen Rolle, sodass diese in dieser Pfeilfunktion zwangsläufig auf das globale Objekt hinweist. Was ist, wenn dies mit der Anrufmethode geändert wird:
var afoo = (a) => {console.log (a); console.log (this);} afoo (1); // 1 // windowvar obj = {name: 'qiutc'}; afoo.call (obj, 2); // 2 // FensterWie Sie sehen können, war der Betrieb des Anrufs, der hier darauf hinweist, nicht erfolgreich, sodass der Schluss gezogen werden kann , dass dies in der Pfeilfunktion bereits bei der Definition (Führen Sie dies in dem Umfang aus, der es definiert) entschieden hat und nichts damit zu tun hat, wie man es nennt und wo es nennt. Keine Operationen, einschließlich (Anruf, Bewerben, Binden) und andere Operationen können dies nicht ändern.
Denken Sie daran, dass die Pfeilfunktion gut ist und dies unverändert bleibt.
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.