Dieses Schlüsselwort in JavaScript. Komplettes * Handbuch

* Höchstwahrscheinlich habe ich etwas verpasst, aber ich bin sicher, dass die Kommentare mir dies sagen werden

Ich 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.

Bild

Inhalt

  1. Einführung
  2. Missverständnisse darüber
  3. 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ört

Dies 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 muss

Es 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.

  1. Sind wir in einer Funktion?


    Kommentar
    Im 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.
  2. 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.

    Kommentar
    Eines 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.
  3. 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.

    Kommentar
    Vielleicht 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.
  4. 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.

    Kommentar
    Die 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.
  5. 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.

    Kommentar
    Fü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); }); //    this === document.    DOM- this  currentTarget [1, 2, 3].forEach(function(){ console.log(this); }); //         ,  undefined. ?     . 
  6. 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.

    Kommentar
    Eine 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.
  7. Wird diese Funktion als Wert einer Objekteigenschaft erhalten und sofort aufgerufen?

    • Ja, this entspricht dem obigen Objekt.
    • Nein: siehe nächster Absatz.

    Kommentar
    Aus 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(); //    object1 -           object1['method'](); //  .        object2.method(); //    object2 -  " ",      ,         
  8. Wird der Code im strengen Modus ausgeführt? ('use strict', ES6-Modul)

    • Ja, this ist undefined .
    • Nein, this entspricht einem globalen Objekt.

    Kommentar
    Wenn 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); })(); //      } } obj.test(); //  ,     obj.   

    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!

Source: https://habr.com/ru/post/de464163/


All Articles