Ganz gleich, welches Wissen wir lernen: Wenn wir uns daran gewöhnen, eine Liste des gelernten Wissens zu erstellen, können wir unser Denken klären und sind eine gute Lernmethode. Sehr empfehlenswert.
Das Folgende ist etwas lang, daher hoffe ich, dass die Leser es geduldig lesen.
Der folgende Inhalt wird in die folgenden Teile unterteilt:
1. Bedeutung
1.1: Die Bedeutung davon
1.2: Die Variabilität davon Punkt
2. Verwendungszwecke
2.1: Globale Umgebung
2.2: Konstruktor
2.3: Objektmethoden
3. Hinweise zu Verwenden Sie
3.1: Vermeiden Sie eine mehrstufige Verschachtelung davon
3.2: Vermeiden Sie dies
in Array-Verarbeitungsmethoden 3.3: Vermeiden Sie dies
in Rückruffunktionen 1 . Bedeutung
1.1: Die Bedeutung davon
Wie in einem Blogbeitrag erwähnt, den ich über die Beziehung zwischen Konstruktoren und dem neuen Schlüsselwort geschrieben habe, gibt das neue Schlüsselwort immer ein Objekt zurück. Dieses Objekt kann das leere Objekt sein, das zurückgegeben wird, wenn new den Konstruktor aufruft, oder es kann ein komplexer Datentyp (einschließlich Objekten, Arrays usw.) sein, der mithilfe der return-Anweisung im Konstruktor zurückgegeben wird.
Ähnlich wie das Schlüsselwort new gibt auch das Schlüsselwort this immer ein Objekt zurück. Genauer gesagt ist es das Objekt, in dem sich die Eigenschaft oder Methode „derzeit“ befindet.
var Keith = { firstName: 'Chou', describe: function() { return this.firstName; } }; console.log(Keith.describe()); //'Chou'
Im obigen Code stellt this.firstName das firstName-Attribut des Objekts dar, in dem sich die Beschreibungsmethode derzeit befindet. Mit anderen Worten: Wenn die Beschreibungsmethode im globalen Bereich aufgerufen wird, ist das aktuelle Objekt, in dem sich die Beschreibungsmethode befindet, Keith, daher wird Keith.firstName aufgerufen.
1.2: Variabilität, auf die hiermit hingewiesen wird
Da die Eigenschaften eines Objekts einem anderen Objekt zugewiesen werden können, ist das aktuelle Objekt, in dem sich die Eigenschaften befinden, variabel. Mit anderen Worten, der Zeiger davon ist variabel.
var Keith = { firstName: 'Chou', describe: function() { return this.firstName; } }; var Rascal={ firstName: 'King' } Rascal.describe=Keith.describe; console.log(Rascal.describe()); //'King'
Im obigen Code ist das Beschreibungsattribut im Keith-Objekt Rascal zugewiesen, sodass das aktuelle Objekt in der Beschreibungsmethode Rascal ist, sodass this.firstName auf Rascal verweist . Da es per Adresse übergeben wird, hat die Änderung von „firstName“ Auswirkungen auf das ursprüngliche Objekt. Dieses Beispiel ist möglicherweise nicht leicht zu verstehen. Schauen Sie sich daher das folgende Beispiel an.
function f(){ return this.firstName; } var Keith = { firstName: 'Chou', describe:f }; var Rascal={ firstName: 'King', describe:f } console.log(Keith.describe()); //'Chou' console.log(Rascal.describe()); //'King'
Im obigen Code wird die Methode in den globalen Bereich verschoben und das Schlüsselwort this wird innerhalb der Funktion f verwendet. Da das Objekt, in dem sich f befindet, unterschiedlich ist, deutet dies auf unterschiedliche Objekte hin.
Im globalen Bereich verweist das Schlüsselwort this auf das Objekt der obersten Ebene (d. h. das Fensterobjekt).
var name='keith'; function person(){ var name='rascal'; return this.name; } console.log(person()); //'keith'
Im obigen Code wird Keith anstelle von Rascal zurückgegeben. Der Grund dafür ist, dass dies auf den globalen Geltungsbereich hinweist. Das Definieren einer Funktion im globalen Bereich verweist standardmäßig auf das Fensterobjekt, nicht auf die Funktion selbst. Wenn Sie jedoch var nicht verwenden, um eine lokale Variable innerhalb der Funktion zu deklarieren, sind die Ergebnisse anders.
var name='keith'; function person(){ name='rascal'; return this.name; } console.log(person()); //'rascal'
Im obigen Code wird var nicht zum Deklarieren einer lokalen Variablen innerhalb der Funktion verwendet, daher ist das Namensattribut innerhalb der Funktion zu diesem Zeitpunkt keine lokale Variable, sondern eine globale Variable. Daher wird das bisherige Namensattribut überschrieben. Wenn Sie sich mit lokalen Variablen und globalen Variablen nicht auskennen, können Sie diesen Artikel lesen.
Solange die Funktion einer anderen Variablen zugewiesen ist, ändert sich der Zeiger dieser.
var Keith={ name:'keith', describe:function(){ return this.name; } } var name='rascal'; var f=Keith.describe; console.log(f()) //'rascal'
Im obigen Code wird Rascal zurückgegeben, nicht Keith. Da Keith.describe der f-Variablen zugewiesen ist und es eine Namensvariable im globalen Bereich gibt, zeigt der this-Punkt der Funktion in Keith auf das Objekt, auf dem f ausgeführt wird (das Objekt der obersten Ebene, d. h. das Fensterobjekt)
Zusammenfassend:
1 In der JavaScript-Sprache ist alles ein Objekt (außer undefiniert und null), und die laufende Umgebung ist auch ein Objekt, sodass Funktionen in a ausgeführt werden bestimmtes Objekt, und das ist dieses Objekt (Umgebung).
2.Die Ausrichtung darauf ist dynamisch. Wenn sich die Funktion im globalen Bereich befindet, zeigt sie auf die globale Umgebung. Wenn sich die Funktion in einem Objekt befindet, zeigt sie auf das Objekt.
2. Nutzungsanlässe
Die Nutzungsanlässe hierfür können in die folgenden Anlässe unterteilt werden.
2.1: Globale Umgebung (globaler Bereich)
Verwenden Sie dieses Objekt im globalen Bereich, der auf das Objekt der obersten Ebene verweist, das das Fensterobjekt ist.
function keith() { return (this === window) } console.log(keith()) //true
Im obigen Code zeigt dies auf das Objektfenster der obersten Ebene, unabhängig davon, ob er sich innerhalb einer Funktion befindet oder nicht, solange er im globalen Bereich ausgeführt wird.
2.2: Konstruktor
Dies im Konstruktor zeigt auf die zu erstellende Objektinstanz.
function Keith() { this.sex = 'boy'; } var person = new Keith(); console.log(person.sex); //'boy'
Im obigen Code wird der Keith-Konstruktor im globalen Bereich definiert, und dann wird der Konstruktor aufgerufen und der Personenobjektinstanz zugewiesen.
Es gibt drei Grundvoraussetzungen für die Konstruktorerstellung: Der erste Buchstabe des Funktionsnamens wird im Konstruktor großgeschrieben; das Schlüsselwort „this“ wird im Konstruktor verwendet, um auf die zu generierende Objektinstanz zu verweisen den Konstruktor und gibt die Objektinstanz zurück.
Wenn Sie mehr über die Beziehung zwischen dem Konstruktor und dem neuen Schlüsselwort erfahren möchten, lesen Sie bitte diesen Artikel.
2.3: Objektmethoden
Wenn eine Methode von Objekt A dem Objekt B zugewiesen wird, ändert sich dies in der Methode vom Zeigen auf Objekt A zum Zeigen auf Objekt B. Seien Sie daher besonders vorsichtig, wenn Sie eine Methode eines Objekts einem anderen Objekt zuweisen.
var keith = { sex: 'boy', foo: function() { return this.sex; } }; var rascal = { sex: 'girl' }; rascal.foo = keith.foo; console.log(keith.foo()); //'boy' console.log(rascal.foo()); //'girl'
Im obigen Code wird Keiths Foo-Funktion Rascal zugewiesen, dann ändert sich der Sinn dieser Funktion von Keith zu Rascal.
如果某个方法位于多层对象的内部,这时为了简化书写,把该方法赋值给一个变量,往往会得到不一样的结果。
var a = { b: { p: 'keith', c: function() { return this.p; } } }; var person = a.b.c; console.log(person()); //undefined
上面代码中,c是两层对象里面的一个方法。为求简便,将其赋值给全局变量person,结果调用时,this指向了顶层对象window。而在window中变量p默认值为undefined。
要解决这个问题,可以只将c所在的对象赋值给person变量,或者是直接调用。
var person = a.b; console.log(person.c()); //'keith' console.log(a.b.c()); //'keith'
3.使用注意点
3.1:避免多层嵌套this
当在闭包中使用多层this,则this都会指向window。
function keith() { console.log(this); return function() { return this; } } keith(); //window keith()(); //window
上面代码中,在一个函数中返回另外一个匿名函数是闭包的特点之一,可以看出,当在闭包中使用this对象都会指向全局作用域中的window对象。
如果在函数外包含一个对象,则内部this指向全局作用域,而外部this对象指向当前作用域。
var o = { f1: function() { console.log(this); (function() { console.log(this) })(); } }; o.f1(); //Object , Window
上面代码包含两层this,结果运行后,第一层指向当前对象,第二层指向全局对象。
实际执行的是如下代码。
function keith() { console.log(this); } var o = { f1: function() { console.log(this); var f2 = keith(); } }; o.f1(); //Object , Window
要实现多层this嵌套,有两种解决方法:
一是在第二层中改用一个指向外层this的变量。
var o = { f1: function() { console.log(this); var that = this; (function() { console.log(that); })(); } }; o.f1(); //Object , Object
上面代码中,定义了局部变量that,固定指向了外层的this,然后在内层中使用that,就不会发生this指向的改变。但是如果函数外部内有嵌套一个对象,this还是会指向全局。
二是Javascript中的严格模式。在严格模式下,如果内部函数的this指向了window对象,就会报错。
var a = { count: 0, fun: function() { 'use strict'; return this.count++; } } var f = a.fun; console.log(f()) //'TypeError: this is undefined'
上面代码中,fun方法使用严格模式声明。把a对象中的fun方法赋值给全局变量f,那么this此时指向window对象,在严格模式下,就会报错。如果函数外部没有嵌套一个对象,那么不会报错,而是会返回undefined。
3.2:避免数组处理方法中的this
数组的map和foreach方法,允许提供一个函数作为参数。这个函数内部不应该使用this。
var keith = { a: 'Hello', b: ['b1', 'b2'], c: function() { this.b.forEach(function(item) { console.log(this.a + ' ' + item); }) } }; keith.c(); //undefined b1 //undefined b2
上面代码中,forEach方法的回调函数中的this,其实指向的是window对象,因此取不到keith.a的值,同上也属于避免多层嵌套this。也就是说,内层的this不指向外部函数,而是指向顶层对象。
要解决这个方法,可以使用that变量来代替回调函数中的this。
var keith = { a: 'Hello', b: ['b1', 'b2'], c: function() { var that = this; this.b.forEach(function(item) { console.log(that.a + ' ' + item); }) } }; keith.c(); //Hello b1 //Hello b2
另外一种方法,就是让this做为forEach方法的第二个参数,来固定它的运行环境。
var keith = { a: 'Hello', b: ['b1', 'b2'], c: function() { this.b.forEach(function(item) { console.log(this.a + ' ' + item); }, this) } }; keith.c(); //Hello b1 //Hello b2
3.3:避免回调函数中的this
回调函数中的this往往会改变指向。
var o = { f: function() { console.log(this === o); } }; o.f(); // true;
上面代码中,调用o对象的f方法,返回true。
但是,如果将f方法指定给某个按钮的click事件,this的指向就变了。
$('button').on('click',o.f);
上面代码中,使用了jquery方法来获取button元素,并绑定click事件。点击按钮后控制台会显示false。原因是此时this不再指向o对象了,而是指向按钮的DOM对象,因为f方法是在按钮对象的环境中被调用的。
总结一下:
a:如果想要多层嵌套this关键字,最常用的解决方法就是使用that变量,固定指向外层的this,然后在内层中使用that变量。就不会发生内层this指向全局的问题。
b:如果在回调函数中使用this关键字,注意this的指向问题。