Was bedeutet 'var that = this;' meine in JavaScript?

351

In einer JavaScript-Datei habe ich gesehen:

function Somefunction(){
   var that = this; 
   ... 
}

Was ist der Zweck that, thisdies zu deklarieren und zuzuweisen ?

Chris
quelle
3
mögliches Duplikat von var self = this?
Bergi
6
Der Hack "dies" und "das" ist für Pfeilfunktionen nicht erforderlich. Mit den Pfeilfunktionen funktioniert "this" wie erwartet. Siehe hier für weitere Details ES6 Im
Pfeilfunktionen
1
Hier wird das Konzept dafür erklärt. scotch.io/@alZami/understanding-this-in-javascript
AL-zami
Eine großartige Erklärung für dieses mysteriöse Verhalten basierend auf dem Kontext hier
RBT
Die neueste und aktualisierte Erklärung finden Sie hier
Sukrit Gupta

Antworten:

486

Ich werde diese Antwort mit einer Illustration beginnen:

var colours = ['red', 'green', 'blue'];
document.getElementById('element').addEventListener('click', function() {
    // this is a reference to the element clicked on

    var that = this;

    colours.forEach(function() {
        // this is undefined
        // that is a reference to the element clicked on
    });
});

Meine Antwort hat dies ursprünglich mit jQuery gezeigt, was sich nur geringfügig unterscheidet:

$('#element').click(function(){
    // this is a reference to the element clicked on

    var that = this;

    $('.elements').each(function(){
        // this is a reference to the current element in the loop
        // that is still a reference to the element clicked on
    });
});

Da sich thishäufig Änderungen ergeben, wenn Sie den Bereich durch Aufrufen einer neuen Funktion ändern, können Sie mit dieser Funktion nicht auf den ursprünglichen Wert zugreifen. Durch Aliasing auf thatkönnen Sie weiterhin auf den ursprünglichen Wert von zugreifen this.

Persönlich mag ich die Verwendung thatals Alias ​​nicht. Es ist selten offensichtlich, worauf es sich bezieht, insbesondere wenn die Funktionen länger als ein paar Zeilen sind. Ich verwende immer einen aussagekräftigeren Alias. In meinen obigen Beispielen würde ich wahrscheinlich verwenden clickedEl.

einsamer Tag
quelle
149
Ich gehe normalerweise mit var self = this;. Das Wort thatscheint zu implizieren, dass die Variable alles ist, ABER this.
David Murdoch
13
@ David Ja, ich habe gedacht , das ist etwas irreführend. Aber wenn es, wie Crockford sagt, eine Konvention ist, ist es ratsam, diesen Weg zu gehen. Ich stimme Ihnen jedoch voll und ganz zu, macht viel mehr Sinn.
El Ronnoco
4
@ El Ronnoco, aber "Er hat graue Haare und einen zotteligen Bart und seine Art erinnert an einen mürrischen alten Mann, der Kinder anschreit, von seinem Rasen zu steigen." - blogging.compendiumblog.com/blog/software-for-humans/0/0/... ;-p
David Murdoch
7
@ ElRonnoco: Das ist allerdings ein Appell an die Autorität. Wenn wir immer nur das tun, was "die berühmten Leute" sagen, dass wir tun sollen, stehen wir vor einer Katastrophe.
Leichtigkeitsrennen im Orbit
3
Die forEachFunktion benötigt ein zweites optionales Argument, nämlich die Bindung der Funktion. colours.forEach(function(){/* 'this' is bound correctly --> */}, this);Daher sollte eine Notiz hinzugefügt werden, die var that = thismit nicht wirklich benötigt wird forEach.
Matt Clarkson
107

Von Crockford

Konventionell machen wir diese Variable privat . Dies wird verwendet, um das Objekt für die privaten Methoden verfügbar zu machen. Dies ist eine Problemumgehung für einen Fehler in der ECMAScript-Sprachspezifikation, der dazu führt, dass dieser für innere Funktionen falsch eingestellt wird.

JS Fiddle

function usesThis(name) {
    this.myName = name;

    function returnMe() {
        return this;        //scope is lost because of the inner function
    }

    return {
        returnMe : returnMe
    }
}

function usesThat(name) {
    var that = this;
    this.myName = name;

    function returnMe() {
        return that;            //scope is baked in with 'that' to the "class"
    }

    return {
        returnMe : returnMe
    }
}

var usesthat = new usesThat('Dave');
var usesthis = new usesThis('John');
alert("UsesThat thinks it's called " + usesthat.returnMe().myName + '\r\n' +
      "UsesThis thinks it's called " + usesthis.returnMe().myName);

Dies warnt ...

UsesThat denkt, es heißt Dave

UsesThis denkt, es heißt undefiniert

El Ronnoco
quelle
2
Danke, fasst es gut genug für mich zusammen.
Chris
3
Ich habe das gelesen, nicht verstanden, weil es keine Details hatte, bei Google gesucht, diese Seite gefunden. Wo ich wieder auf den gleichen Satz hingewiesen werde. Daher die Ablehnung.
Aditya MP
3
Das ist ein fairer Punkt, ich würde sagen, dass jemand, der mit JavaScript nicht vertraut ist, Schwierigkeiten haben würde, das Konzept allein anhand meiner Antwort zu erfassen. Ich habe sehr kurz geantwortet (und ich habe auf die Seite verlinkt, nach der Sie gegoogelt haben). Ich würde sagen, die Antwort von lonesomeday ist die klarste, obwohl ich sie in einfachem JS im Gegensatz zu einem jQuery-Beispiel immer noch vorgezogen hätte.
El Ronnoco
16
Ich nehme keine Beleidigung. Es ist schön, jemanden zu sehen, der beim Downvoting Kommentare abgibt!
El Ronnoco
4
Das Problem mit Crockfords Antwort ist, dass die thatVariable in seinem Beispiel überhaupt nicht verwendet wird. Es sieht so aus, als würde das Erstellen einer Variablen thisden Rest des Codes beeinflussen.
r3m0t
86

Dies ist ein Hack, um innere Funktionen (Funktionen, die in anderen Funktionen definiert sind) besser funktionieren zu lassen, als sie sollten. Wenn Sie in Javascript eine Funktion in einer anderen definieren, wird diese thisautomatisch auf den globalen Bereich gesetzt. Dies kann verwirrend sein, da Sie thisdenselben Wert wie in der äußeren Funktion erwarten .

var car = {};
car.starter = {};

car.start = function(){
    var that = this;

    // you can access car.starter inside this method with 'this'
    this.starter.active = false;

    var activateStarter = function(){
        // 'this' now points to the global scope
        // 'this.starter' is undefined, so we use 'that' instead.
        that.starter.active = true;

        // you could also use car.starter, but using 'that' gives
        // us more consistency and flexibility
    };

    activateStarter();

};

Dies ist insbesondere dann ein Problem, wenn Sie eine Funktion als Methode eines Objekts car.starterstellen (wie im Beispiel) und dann eine Funktion innerhalb dieser Methode erstellen (wie im Beispiel activateStarter). In der obersten Ebene zeigt die Methode thisauf das Objekt, es ist eine Methode von (in diesem Fall car), aber in der inneren Funktion zeigt sie thisjetzt auf den globalen Bereich. Das ist ein Schmerz.

Das Erstellen einer Variablen, die gemäß Konvention in beiden Bereichen verwendet werden soll, ist eine Lösung für dieses sehr allgemeine Problem mit Javascript (obwohl es auch in jquery-Funktionen nützlich ist). Aus diesem Grund wird der sehr allgemein klingende Name thatverwendet. Es ist eine leicht erkennbare Konvention zur Überwindung eines Sprachmangels.

Wie El Ronnoco andeutet, hält Douglas Crockford dies für eine gute Idee.

Waylon Flinn
quelle
8
Ich nehme an, dies ist eine nützlichere Antwort als eine akzeptierte. Weil es den Grund klarstellt, warum Crockford "das" erfunden hat, während die Antwort auf jQuery dies nicht tut.
Konstantin Smolyanin
4
Dies ist tatsächlich ein besseres Beispiel als die akzeptierte Antwort. Es erklärt, wie es ist als "ein Fehler in der ECMAScript-Sprachspezifikation, der dazu führt, dass dies für innere Funktionen falsch eingestellt wird", sagte Douglas.
Kakacii
1
Möglicherweise möchten Sie die Grammatik jedoch korrigieren. Ich weiß, dass es eher ein Tippfehler ist, aber es könnte Javascript-Anfänger verwirren, da diese Frage eher für Anfänger geeignet ist. Ich meine, es sollte sein: var car = {}; car.starter = {}; car.start = function () {...}
kakacii
1
@ Kakacii Danke. Jetzt behoben.
Waylon Flinn
9

Die Verwendung von thatist nicht wirklich erforderlich, wenn Sie eine Problemumgehung mit der Verwendung von call()oder durchführen apply():

var car = {};
car.starter = {};

car.start = function(){
    this.starter.active = false;

    var activateStarter = function(){
        // 'this' now points to our main object
        this.starter.active = true;
    };

    activateStarter.apply(this);
};
Adela
quelle
3

Manchmal thiskann auf einen anderen Bereich und auf etwas anderes verwiesen werden. Nehmen wir beispielsweise an, Sie möchten in diesem Fall eine Konstruktormethode innerhalb eines DOM-Ereignisses aufrufenthis bezieht sich dies auf das DOM-Element und nicht auf das erstellte Objekt.

HTML

<button id="button">Alert Name</button>

JS

var Person = function(name) {
  this.name = name;
  var that = this;
  this.sayHi = function() {
    alert(that.name);
  };
};

var ahmad = new Person('Ahmad');
var element = document.getElementById('button');
element.addEventListener('click', ahmad.sayHi); // => Ahmad

Demo

Die obige Lösung geht davon aus this, dass thatwir dann auf die name-Eigenschaft innerhalb der sayHiMethode von zugreifen könnenthat , sodass diese ohne Probleme innerhalb des DOM-Aufrufs aufgerufen werden kann.

Eine andere Lösung besteht darin, ein leeres thatObjekt zuzuweisen , ihm Eigenschaften und Methoden hinzuzufügen und es dann zurückzugeben. Aber mit dieser Lösung haben Sie prototypeden Konstruktor verloren.

var Person = function(name) {
  var that = {};
  that.name = name;
  that.sayHi = function() {
    alert(that.name);
  };
  return that;
};
Ahmad Ajmi
quelle
2

Hier ist ein Beispiel `

$(document).ready(function() {
        var lastItem = null;
        $(".our-work-group > p > a").click(function(e) {
            e.preventDefault();

            var item = $(this).html(); //Here value of "this" is ".our-work-group > p > a"
            if (item == lastItem) {
                lastItem = null;
                $('.our-work-single-page').show();
            } else {
                lastItem = item;
                $('.our-work-single-page').each(function() {
                    var imgAlt = $(this).find('img').attr('alt'); //Here value of "this" is '.our-work-single-page'. 
                    if (imgAlt != item) {
                        $(this).hide();
                    } else {
                        $(this).show();
                    }
                });
            }

        });
    });`

Sie können also sehen, dass dieser Wert zwei verschiedene Werte ist, abhängig von dem DOM-Element, auf das Sie abzielen. Wenn Sie jedoch "das" zum obigen Code hinzufügen, ändern Sie den Wert von "this", auf das Sie abzielen.

`$(document).ready(function() {
        var lastItem = null;
        $(".our-work-group > p > a").click(function(e) {
            e.preventDefault();
            var item = $(this).html(); //Here value of "this" is ".our-work-group > p > a"
            if (item == lastItem) {
                lastItem = null;
                var that = this;
                $('.our-work-single-page').show();
            } else {
                lastItem = item;
                $('.our-work-single-page').each(function() {
                   ***$(that).css("background-color", "#ffe700");*** //Here value of "that" is ".our-work-group > p > a"....
                    var imgAlt = $(this).find('img').attr('alt'); 
                    if (imgAlt != item) {
                        $(this).hide();
                    } else {
                        $(this).show();
                    }
                });
            }

        });
    });`

..... $ (that) .css ("Hintergrundfarbe", "# ffe700"); // Hier ist der Wert von "that" ".our-work-group> p> a", weil der Wert von var that = this; Obwohl wir uns bei "this" = ".our-work-single-page" befinden, können wir "that" dennoch verwenden, um das vorherige DOM-Element zu manipulieren.

stacksonstacksonstacks
quelle