* Höchstwahrscheinlich habe ich etwas verpasst, aber ich bin sicher, dass die Kommentare mir dies sagen werdenIch schreibe diesen Artikel für meine persönlichen Bedürfnisse. Es ist geplant, dass es die Antworten auf alle Fragen enthält, die mir die Schüler zu diesem Thema stellen. Wenn es jemand anderem nützlich ist - großartig.
Inhalt
- Einführung
- Missverständnisse darüber
- Wie man den Wert davon bestimmt
Einführung
Das
this
ist eine der verwirrendsten Funktionen der JavaScript-Sprache. Aus Java stammend, sollte es bei der Implementierung von OOP helfen. Ich habe einige Zeit in Java geschrieben, und ich muss sagen, dass ich in dieser Zeit vielleicht einmal daran gezweifelt habe, was
this
an einer bestimmten Stelle im Code bedeutet. In JavaScript können solche Zweifel jeden Tag auftreten - zumindest bis Sie einige einfache, aber nicht offensichtliche Regeln lernen.
Missverständnisse darüber
Es gibt mehrere häufige Missverständnisse in Bezug auf dieses Schlüsselwort. Ich möchte sie schnell zerstreuen, bevor ich zur Sache komme.
Dies ist ein lexikalischer Kontext.Dieser Eindruck entsteht häufig bei Anfängern. Es scheint ihnen, dass
this
ein Objekt ist, in dem wie Eigenschaften alle Variablen in diesem Bereich gespeichert sind. Dieses Missverständnis beruht auf der Tatsache, dass dies in einem bestimmten Fall grob gesagt der Fall ist. Wenn wir uns auf der höchsten Ebene befinden, entspricht
this
dem
window
(im Fall eines regulären Skripts im Browser). Und wie wir wissen, sind alle auf der obersten Ebene deklarierten Variablen als
window
verfügbar.
Im Allgemeinen ist dies nicht wahr. Dies ist leicht zu überprüfen.
function test(){ const a = " , "; console.log(this.a); } test();
Dies ist das Objekt, zu dem die Methode gehörtDies gilt wiederum in vielen speziellen Fällen, jedoch nicht immer. Wichtig ist, wie die Funktion aufgerufen wird und nicht, ob sie eine Eigenschaft eines Objekts ist. Dies ist selbst aus einer sehr einfachen Logik verständlich: Angenommen, dieselbe Funktion ist eine Eigenschaft von zwei Objekten gleichzeitig.
const f = function(){ console.log(this); } const object1 = { method: f }; const object2 = { method: f };
Also, welches dieser Objekte wird sie das sein?
Wichtig! Selbst wenn ein Objekt mit ES6-Klassen erstellt wird, garantiert dies überhaupt nicht, dass seine Methode dies immer hat. Lassen Sie sich nicht von der Ähnlichkeit mit Klassen aus „normalen“ Sprachen täuschen.
Dies ist eine Jedi-Technik, die, sobald sie erlernt wurde, überall angewendet werden mussEs ist am besten,
this
nach Möglichkeit zu vermeiden. Der einzige Fall, in dem dies vollständig gerechtfertigt ist, ist OOP. An anderer Stelle ist
this
nicht nur böse, sondern normalerweise ein Overkill, der den Code verwirrt. Im Wesentlichen handelt es sich
this
um ein zusätzliches Argument „minus das erste“ für die Funktion, das dort auf komplizierte, nicht offensichtliche Weise an den Anfänger weitergegeben wird. Mit hoher Wahrscheinlichkeit kann es durch das übliche Argument ersetzt werden, und es wird nur besser.
Wie man den Wert davon bestimmt
Hier werde ich versuchen, einen strengen und präzisen Algorithmus anzugeben, mit dem selbst ein unerfahrener Codierer verstehen kann, was
this
in seinem speziellen Fall bedeutet. Ausführlichere Erklärungen werden unter den Spoilern versteckt, um den visuellen Raum nicht zu überladen.
- Sind wir in einer Funktion?
KommentarIm Code der obersten Ebene (nicht in einer Funktion) bezieht sich this
immer auf ein globales Objekt. Bei einem regulären Skript im Browser handelt es sich um ein window
. Im Allgemeinen gibt es jedoch verschiedene Fälle.
- Befinden wir uns innerhalb der Pfeilfunktion?
- Ja: Der Wert ist der gleiche wie in der Funktion, die eine Ebene höher ist (d. H. Diese enthält). Kehren Sie zum vorherigen Schritt zurück und wiederholen Sie den Algorithmus dafür. Wenn die Funktion in keinem anderen enthalten ist,
this
es sich um ein globales Objekt. - Nein: siehe nächster Absatz.
KommentarEines der Hauptmerkmale von Pfeilfunktionen ist das sogenannte „lexikalische this
“. Dies bedeutet, dass der Wert this
Funktion in der Pfeilfunktion ausschließlich davon abhängt, wo (in welchem lexikalischen Kontext) sie erstellt wurde, und nicht davon abhängt, wie sie später aufgerufen wurde. Manchmal ist dies nicht das, was wir brauchen, aber häufiger macht es Pfeilfunktionen sehr bequem und vorhersehbar.
- Wird diese Funktion als Konstruktor aufgerufen (mit dem neuen Operator)?
- Ja,
this
bezieht sich auf ein neues Objekt, das sich "im Aufbau" befindet. - Nein: siehe nächster Absatz.
KommentarVielleicht lohnt es sich, den Fall separat anzugeben, wenn es um den Konstruktor der geerbten ES6-Klasse geht. Vor dem Aufruf von super()
hat this
keinen Wert (der Zugriff darauf führt zu einem Fehler), und nach dem Aufruf von super()
entspricht es dem neuen Objekt der übergeordneten Klasse.
- Wird diese Funktion mit der Bindung erstellt ?
- Ja, der Wert von
this
entspricht dem Wert des ersten Arguments, das wir beim Erstellen dieser Funktion an die bind
Methode übergeben haben. - Nein: siehe nächster Absatz.
KommentarDie bind
Methode erstellt eine Kopie der Funktion und korrigiert this
und optional die ersten Argumente dafür. Tatsächlich wird dadurch nicht nur eine Kopie der Funktion erstellt, sondern, wie ich zitiere, ein „exotisches BoundFunction-Objekt“. Seine Exotik manifestiert sich insbesondere darin, dass wir dies durch einen wiederholten Aufruf zur bind
nicht mehr ändern this
. Genau genommen sollte die Antwort in diesem Absatz daher wie folgt formuliert werden: Wenn ja, dann entspricht this
dem ersten Argument des ersten Aufrufs zum bind
, das zur Erstellung dieser Funktion geführt hat.
- Wird diese Funktion irgendwo als Rückruf oder Handler übergeben?
- Ja, der Herr allein weiß, was dies bedeuten wird, wenn er gerufen wird. Lesen Sie die Dokumentation für die Ursache.
- Nein: siehe nächster Absatz.
KommentarFür eine nicht pfeil- und gebundene Funktion hängt der Wert
this
ab, unter welchen Umständen sie aufgerufen wurde. Wenn Sie es nicht persönlich anrufen, sondern irgendwo weitergeben, kann
this
Wert durch einen unbekannten Wert ersetzt werden oder nicht.
Beispiele:
`use strict` document.addEventListener('keydown', function(){ console.log(this); });
- Diese Funktion wird mit dem Apply oder Call aufgerufen .
- Ja, in diesem Fall entspricht dies dem ersten Argument, das an die entsprechende Methode übergeben wurde.
- Nein: siehe nächster Absatz.
KommentarEine andere Möglichkeit, dies explizit festzulegen. Genauer gesagt, zwei. In this
Hinsicht this
keinen Unterschied zwischen apply
und call
. Der einzige Unterschied besteht darin, wie die restlichen Argumente übergeben werden.
- Wird diese Funktion als Wert einer Objekteigenschaft erhalten und sofort aufgerufen?
- Ja,
this
entspricht dem obigen Objekt. - Nein: siehe nächster Absatz.
KommentarAus diesem Mechanismus (sowie aus der Erfahrung mit anderen Sprachen) wachsen die Beine aus dem Glauben, dass "
this
das Objekt ist, dessen Methode wir genannt haben". Vielleicht schreibe ich einfach den Code.
'use strict'; const object1 = { method: function(){ console.log(this); } } const object2 = { method: object1.method } object1.method();
- Wird der Code im strengen Modus ausgeführt? ('use strict', ES6-Modul)
- Ja,
this
ist undefined
. - Nein,
this
entspricht einem globalen Objekt.
KommentarWenn wir an diesen Punkt gelangen, wird
this
durch keinen der Mechanismen festgelegt, die das Festlegen ermöglichen. Es gibt verschiedene Missverständnisse darüber, wie dies sonst weitergegeben werden kann. Zum Beispiel sagen sie mir in Interviews oft so etwas:
const obj = { test: function(){ (function(){ console.log(this); })();
Oder, wie ich im Abschnitt „Missverständnisse“ sagte, denken viele Leute, wenn eine Funktion eine Methode eines Objekts ist, das mit ES6-Klassen erstellt wurde, ist dies immer gleich dem darin enthaltenen Objekt. Dies ist auch nicht wahr.
Wenn wir also an diesen Punkt gelangen, spielen die anderen Umstände des Aufrufs unserer Funktion keine Rolle. Und es kommt darauf an, ob wir uns im strengen Modus befinden oder nicht.
In der Vergangenheit wurde als "Standard" ein globales Objekt an solche Funktionen übergeben. Dieser Ansatz wurde später als unsicher erkannt. ES5 hat einen strengen Modus eingeführt, der viele Probleme früherer Versionen von ECMAScript behebt. Es ist in der Direktive 'use strict' am Anfang einer Datei oder Funktion enthalten. In diesem Modus ist der "Standard" -Wert
undefined
.
In ES6-Modulen ist der strikte Modus standardmäßig aktiviert.
Es gibt auch andere Mechanismen zum Einschließen des strengen Modus. In NodeJS kann beispielsweise der strikte Modus für alle Dateien mit dem
--use-strict
.
Das ist im Allgemeinen alles. Die Bestimmung des Wertes ist natürlich weniger einfach als wir möchten, aber es ist nicht so schwierig, wie es scheinen mag. Lernen Sie diesen Algorithmus als Multiplikationstabelle - und Sie werden nie wieder Probleme damit
this
. Solche Dinge.
PS-Benutzer
Aingis schlug vor, dass bei Verwendung des
with- Konstrukts das als Kontext übergebene Objekt das globale Objekt ersetzt. Vielleicht werde ich dies nicht in meinen Klassifikator eintragen, weil die Chance, sich 2019+ zu treffen, eher gering ist. Dies ist jedoch auf jeden Fall ein interessanter Punkt.
Der PPS-Benutzer
rqrqrqrq schlug vor, dass
new
höhere Priorität als
bind
. Die entsprechende Überarbeitung des Klassifikators wurde bereits vorgenommen. Vielen Dank!