JavaScript-"this"關鍵字

全域this

在全域環境中取用this,會指向全域物件。

1
console.log(this);

而在瀏覽器中執行,瀏覽器的全域物件為window物件。

函式中的this

每當一個函式被呼叫,會創造出一個新的執行環境,且同時會產生一個未曾宣告的”this變數”,然而,”this變數”的值指向哪個物件,會依據函式在何處被呼叫而決定。

下述例子中,先有一個函式,其中log出this。當使用a()呼叫執行,代表執行該函式的程式屬性(code),也就是函式中的全部程式。

1
2
3
4
function a(){
console.log(this);
}
a();

實行結果,在a函式中的this,同樣指向全域物件的Window。

下述另一個案例,使用函式表示式來設定一個物件函式,再將之assign給變數b。

1
2
3
4
var b = function(){
console.log(this);
}
b();

執行結果,在b函式中的this,同樣指向全域物件的Window。

函式中創建全域物件

下述程式碼統整目前的案例,有三個執行環境被產生:

  1. 全域環境
  2. 呼叫函式a,產生的區域環境
  3. 呼叫函式b,產生的區域環境

在每個執行環境中,分別產生三個不同的this變數,可是三個this都指向同一個位址(同一個全域物件window)。

1
2
3
4
5
6
7
8
9
function a(){
console.log(this);
}
var b = function(){
console.log(this);
}

a();
b();

小結,在函式中呼叫this,會指向全域變數,而非函式本身。

在下述程式碼中,在a函式中的this代表全域物件Window,所以宣告this.newVar代表宣告一個全域變數。
也因此,直接在全域log出變數newVar不會出錯,因為它確實在執行a函式時,就已經被宣告出來了。

1
2
3
4
5
6
function a(){
console.log(this);
this.newVar = 'hello';
}
a();
console.log(newVar);

執行結果,會將newVar印出值為’hello’,且若點開Window物件中,也可以看到確實有一個變數為newVar。

物件中的this

宣告一個物件c,在其中有屬性name,也有方法log,接著用c.log()執行物件c中的方法log。

1
2
3
4
5
6
7
var c = {
name:'The c obj',
log: function(){
console.log(this);
}
}
c.log();

執行結果,在物件c的方法log中的this,代表物件c。

小結,當函式是物件的方法時,在其中呼叫的this變數會指向該物件本身。換句話說,this變數會指向包含它的物件。

在物件方法中修改物件的屬性

物件c的log方法中,因為this代表物件c本身,所以用this.name代表物件c的屬性,藉此更改其值。

1
2
3
4
5
6
7
8
var c = {
name:'The c obj',
log: function(){
this.name = 'update c obj'
console.log(this);
}
}
c.log();

執行結果,可以看到物件c的屬性name確實被修改了。

self宣告模式,解決JS的不完美

在物件d的方法log中,宣告一個函式物件setName,在其中的this變數並不會指向物件d,而是指向全域物件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var d = {
name: 'The d obj',
log: function(){
this.name = 'update d obj';
console.log(this.name);

var setName = function(newName){
this.name = newName;//這裡的this會設置到全域物件window中
console.log(this.name);
}
setName('update again!');
console.log(this.name);
}
}

許多人會認為這是JavaScript本身的bug,但是事實上他就是這麼運作,因此若要避免產生錯誤,業界有一套常用的模式來應付這種狀況。

通常會在物件方法的第一行,宣告一個新的變數self,並且讓this指派給他,因為物件的assign是call by reference,因此self會指向this同一個位置,確保兩者指向同一物件e。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var e = {
name: 'The e obj',
log: function(){
var self = this;
self.name = 'update e obj';
console.log(self.name);

var setName = function(newName){
self.name = newName;//這裡的this會設置到全域物件window中
console.log(self.name);
}
setName('update e again!');
console.log(self.name);
}
}
e.log();

當有了一個變數self,之後修改或呼叫,就直接用self以確保是指向物件e。

© 2020 Leah's Blog All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero