Um dies zu verstehen, basierend auf dem Ort, an dem sich dies befindet, kann die Situation grob in 3 Typen unterteilt werden:
1. In der Funktion: Dies ist normalerweise ein impliziter Parameter.
2. Außerhalb der Funktion (im oberen Bereich): Im Browser bezieht sich dies auf das globale Objekt; in node.js bezieht sich auf die Exporte von Modulen.
3. Die an eval () übergebene Zeichenfolge: Wenn Eval () direkt aufgerufen wird, bezieht sich dies auf das aktuelle Objekt; Wenn eval () indirekt bezeichnet wird, bezieht sich dies auf das globale Objekt.
Wir haben entsprechende Tests für diese Kategorien durchgeführt:
1. Dies in der Funktion
Funktionen können grundsätzlich alle aufgerufenen Strukturen in JS darstellen. Dies ist daher auch das häufigste Szenario, in dem dies verwendet wird, und Funktionen können in die folgenden drei Rollen unterteilt werden:
Echte Funktionen
Konstruktor
Verfahren
1.1 dies in realen Funktionen
In realen Funktionen ist der Wert davon ein Muster, das von dem Kontext abhängt, in dem es sich befindet.
Schlampiger Modus: Dies bezieht sich auf ein globales Objekt (Fenster im Browser).
Die Codekopie lautet wie folgt:
Funktion sloppyfunc () {
console.log (this === Fenster); // WAHR
}
sloppyfunc ();
Strenge Modus: Der Wert davon ist undefiniert.
Die Codekopie lautet wie folgt:
Funktion strictfunc () {
"Strikte";
console.log (this === undefiniert); // WAHR
}
strictfunc ();
Dies ist ein implizite Parameter einer Funktion, daher ist sein Wert immer der gleiche. Sie können diesen Wert jedoch mithilfe von CALL () oder anwenden () -Methoden definieren, um den Wert anzuzeigen.
Die Codekopie lautet wie folgt:
Funktion func (arg1, arg2) {
console.log (this); // 1
console.log (arg1); // 2
console.log (arg2); // 3
}
func.call (1, 2, 3); // (this, arg1, arg2)
Func.Apply (1, [2, 3]); // (this, arrayWithargs)
1.2 dies im Konstruktor
Sie können eine Funktion als Konstruktor über neu verwenden. Die neue Operation erstellt ein neues Objekt und übergibt dieses Objekt in den Konstruktor.
Die Codekopie lautet wie folgt:
var hat das gerettet;
Funktion Const () {
saved this = this;
}
var inst = new Const ();
console.log (savedthis === inst); // WAHR
Das Implementierungsprinzip des neuen Betriebs in JS wird im folgenden Code grob angezeigt (hier für eine genauere Implementierung ist diese Implementierung auch komplizierter):
Die Codekopie lautet wie folgt:
Funktion Newoperator (Const, ArrayWithargs) {
var ThisValue = Object.create (Const.Prototype);
Const.Apply (Thisvalue, ArrayWithargs);
kehren Sie Thisvalue zurück;
}
1.3 dies in der Methode
In den Methoden ist die Verwendung davon in der traditionellen objektorientierten Sprache eher betrifft: Der Empfänger wies darauf hin, dh auf das Objekt, das diese Methode enthält.
Die Codekopie lautet wie folgt:
var obj = {
Methode: function () {
console.log (this === obj); // WAHR
}
}
Obj.Method ();
2. Dies im Umfang
Im Browser ist Scope der globale Bereich, und dies bezieht sich auf dieses globale Objekt (wie Fenster):
Die Codekopie lautet wie folgt:
<Script>
console.log (this === Fenster); // WAHR
</script>
In node.js führen Sie normalerweise Funktionen in Modulen aus. Daher ist der Umfang der obersten Ebene ein ganz besonderer Modulbereich:
Die Codekopie lautet wie folgt:
// `global` (nicht` window`) Siehe globales Objekt:
console.log (math === global.math); // WAHR
// `Dies 'bezieht sich nicht auf das globale Objekt:
console.log (this! == global); // WAHR
// `Dies" bezieht sich auf die Exporte eines Moduls:
console.log (this === module.exports); // WAHR
3.. Dies in eval ()
eval () kann direkt aufgerufen werden (indem der Funktionsname 'eval') oder indirekt (auf andere Weise wie CALL ()) aufgerufen werden. Weitere Informationen finden Sie hier.
Die Codekopie lautet wie folgt:
// echte Funktionen
Funktion sloppyfunc () {
console.log (eval ('this') === Fenster); // WAHR
}
sloppyfunc ();
Funktion strictfunc () {
"Strikte";
console.log (eval ('this') === undefiniert); // WAHR
}
strictfunc ();
// Konstruktoren
var hat das gerettet;
Funktion Const () {
saved this = eval ('this');
}
var inst = new Const ();
console.log (savedthis === inst); // WAHR
// Methoden
var obj = {
Methode: function () {
console.log (eval ('this') === obj); // WAHR
}
}
Obj.Method ();
4. Fallen im Zusammenhang mit diesem
Sie sollten vorsichtig mit den 3 Fallen im Zusammenhang mit diesem unten sein, die unten eingeführt werden. Beachten Sie, dass im folgenden Beispiel die Verwendung des strengen Modus die Sicherheit des Codes verbessern kann. Da in realen Funktionen der Wert davon undefiniert ist, werden Sie eine Warnung erhalten, wenn etwas schief geht.
4.1 vergessen, neu zu verwenden
Wenn Sie NEW nicht zum Konstruktor verwenden, verwenden Sie tatsächlich eine echte Funktion. Dies ist also nicht der Wert, den Sie erwarten. Im schlampigen Modus verweist dies auf das Fenster und Sie erstellen globale Variablen:
Die Codekopie lautet wie folgt:
Funktionspunkt (x, y) {
this.x = x;
this.y = y;
}
var p = Punkt (7, 5); // Wir vergessen neu!
console.log (p === undefiniert); // WAHR
// Globale Variablen wurden erstellt:
console.log (x); // 7
console.log (y); // 5
Wenn Sie jedoch den strengen Modus verwenden, erhalten Sie immer noch eine Warnung (this === undefiniert):
Die Codekopie lautet wie folgt:
Funktionspunkt (x, y) {
"Strikte";
this.x = x;
this.y = y;
}
var p = Punkt (7, 5);
// TypeRror: Die Eigenschaft 'x' kann nicht und definiert nicht festgelegt werden
4.2 Unangemessene Verwendung Methode
Wenn Sie direkt den Wert einer Methode erhalten (nicht aufrufen), verwenden Sie diese Methode als Funktion. Wenn Sie eine Methode als Parameter in eine Funktion oder eine Aufrufmethode übergeben möchten, werden Sie dies höchstwahrscheinlich tun. Dies ist bei SetTimeOut () und Registrierungsereignis Handlern der Fall. Ich werde die Callit () -Methode verwenden, um dieses Szenario zu simulieren:
Die Codekopie lautet wie folgt:
/** Ähnlich wie setTimeout () und setimmediate ()*//
Funktion Callit (func) {
func ();
}
Wenn Sie eine Methode als Funktion im schlampigen Modus aufrufen, ist * dies * auf das globale Objekt verweist, sodass die anschließend erstellte globale Variablen sind.
Die Codekopie lautet wie folgt:
var counter = {
Zählen: 0,
// Sloppy-Mode-Methode
Inc: function () {
this.count ++;
}
}
Callit (counter.inc);
// hat nicht funktioniert:
console.log (counter.count); // 0
// Stattdessen wurde eine globale Variable erstellt
// (NAN ist das Ergebnis der Anwendung ++ auf undefinierte):
console.log (count); // nan
Wenn Sie dies im strengen Modus tun, ist dies undefiniert und Sie werden immer noch nicht das gewünschte Ergebnis erhalten, aber zumindest erhalten Sie eine Warnung:
Die Codekopie lautet wie folgt:
var counter = {
Zählen: 0,
// Strict-Mode-Methode
Inc: function () {
"Strikte";
this.count ++;
}
}
Callit (counter.inc);
// Typeerror: Eigentum kann 'Graf' von undefined nicht lesen
console.log (counter.count);
Um die erwarteten Ergebnisse zu erzielen, können Sie Bind () verwenden:
Die Codekopie lautet wie folgt:
var counter = {
Zählen: 0,
Inc: function () {
this.count ++;
}
}
Callit (counter.inc.bind (counter));
// Es hat funktioniert!
console.log (counter.count); // 1
Bind () erstellt eine andere Funktion, die diesen Wert immer auf Konter setzen kann.
4.3 Verstecke das
Wenn Sie Funktionen in Methoden verwenden, ignorieren Sie häufig, dass Funktionen dies haben. Dies unterscheidet sich von der Methode, sodass Sie diese beiden nicht zusammen mischen können. Weitere Informationen finden Sie im folgenden Code:
Die Codekopie lautet wie folgt:
var obj = {
Name: 'Jane',
Freunde: ['Tarzan', 'Cheeta'],
Schleife: function () {
"Strikte";
this.friends.foreach (
Funktion (Freund) {
console.log (this.name+'kennt'+Freund);
}
);
}
};
obj.loop ();
// TypeError: Eigenschaftsname von undefined kann nicht gelesen werden
Dies kann in der Funktion im obigen Beispiel nicht verwendet werden, da der Wert dieser Funktion undefiniert ist, was sich in der Methodenschleife () von dieser unterscheidet. Im Folgenden finden Sie drei Ideen, um dieses Problem zu lösen:
1. Das = dies zu einer Variablen zuweisen, damit dies explizit manifestiert (außer dass Selbst auch ein sehr häufiger Variablenname ist, der verwendet wird) und dann diese Variable verwenden:
Die Codekopie lautet wie folgt:
Schleife: function () {
"Strikte";
var das = dies;
this.friends.foreach (Funktion (Freund) {
console.log (that.name+'Wissen'+Freund);
});
}
2. Bind (). Verwenden Sie Bind (), um eine Funktion zu erstellen. Diese Funktion enthält immer den Wert, den Sie übergeben möchten (im folgenden Beispiel diese Methode):
Die Codekopie lautet wie folgt:
Schleife: function () {
"Strikte";
this.friends.foreach (Funktion (Freund) {
console.log (this.name+'kennt'+Freund);
} .bind (this));
}
3. Verwenden Sie den zweiten Parameter von foreach. Der zweite Parameter von foreach wird in die Rückruffunktion übergeben und als die Rückruffunktion verwendet.
Die Codekopie lautet wie folgt:
Schleife: function () {
"Strikte";
this.friends.foreach (Funktion (Freund) {
console.log (this.name+'kennt'+Freund);
}, Das);
}
5. Best Practices
Theoretisch denke ich, dass die wirkliche Funktion dies nicht selbst gehört, und die obige Lösung basiert auch auf dieser Idee. ECMascript 6 verwendet die Pfeilfunktion, um diesen Effekt zu erzielen, was eine Funktion ist, die diese nicht hat. In einer solchen Funktion können Sie dies nach Belieben verwenden, ohne sich Sorgen darüber zu machen, ob es implizite Existenz gibt.
Die Codekopie lautet wie folgt:
Schleife: function () {
"Strikte";
// Der Parameter von foreach () ist eine Pfeilfunktion
this.friends.foreach (Freund => {
// `this` ist Loops` this`
console.log (this.name+'kennt'+Freund);
});
}
Ich mag keine APIs als zusätzlichen Parameter für eine reale Funktion:
Die Codekopie lautet wie folgt:
voran (function () {
this.addMatchers ({{
tobeinrange: Funktion (Start, Ende) {
...
}
});
});
Das Schreiben eines impliziten Parameters, der explizit übergeben wird, erscheint der Code besser zu verstehen, und dies steht im Einklang mit den Anforderungen der Pfeilfunktion:
Die Codekopie lautet wie folgt:
voran (api => {
api.addmatchers ({{
tobeinrange (Start, Ende) {
...
}
});
});