this 是 Javascript 的一個關鍵字。隨著使用場合不同,this 的值也會產生變化。但原則上就是:
this 指的是,調用函數的那個對象。
以下分成五種常見的狀況來探討:
在 C# 裡,一個物件內的成員函式裡的 this 指的即是該成員函式所在之物件,但在 Javascript 裡的 this 看的是是誰調用該函式,而不是看該函式被定義在哪個物件內。
公式:
物件.函式(); //函式內的 this 指向該物件
舉例:
var obj = {
x: 20,
f: function(){ console.log(this.x); } //20
};
obj.f(); //由於調用 f 函式時,點前面物件為 obj,故 f 內的 this 指向 obj,則輸出為 20。
obj.innerobj = {
x: 30,
f: function() { console.log(this.x); } //30
}
obj.innerobj.f(); //由於調用 f 函式時,點前面物件為 obj.innerobj,故 f 內的 this 指向 obj.innerobj,則輸出為 30。
如果調用函式的前方並未有物件,則函式內 this 就指向全域物件。
- 瀏覽器內全域物件為 window 物件。
- node.js 中全域物件則為 GLOBAL 物件。
公式:
函式(); //函式內的 this 指向全域物件
舉例:
var x = 10;
var f = function() {
console.log(this.x); //10
};
f(); //由於調用 f 函式時,前方並未有[物件.]的形式,故 f 內的 this 指向全域物件,則輸出全域變數的 10。
call 與 apply 都是呼叫該函式並讓該函式的 this 指向給予 call 或 apply 的第一個參數。 至於call 和 apply 的差別則是在於其後面給予被調用之函式的參數放入的方法不同,一個是直接攤平放在第二個以後的參數;一個是直接放入一個裡面放要給予之參數的陣列。
公式:
(A物件.)函式.call(B物件, 參數1, 參數2, ...); //函式的 this 指向 B 物件 (若 B 物件為 null,則指向全域物件) (A物件.)函式.apply(B物件, [參數1, 參數2, ...]); //函式的 this 指向 B 物件 (若 B 物件為 null,則指向全域物件)
舉例 1. call 時有帶入參數:
var obj1 = {
x: 20,
f: function(){ console.log(this.x); } //30
};
var obj2 = {
x: 30
};
obj1.f.call(obj2); //利用 call 指派 f 的 this 為指向 obj2,故輸出為 30
舉例 2. call 時無帶入參數:
var x = 10;
var obj1 = {
x: 20,
f: function(){ console.log(this.x); } //10
};
var obj2 = {
x: 30
};
obj1.f.call(); //利用 call 指派 f 的 this 為指向 obj2,故輸出為 10
若將函式當作建構式 (constructor) 來用,則內部的 this 則指向於 new 所產生之新物件。
公式:
new 建構式(); //建構式內之 this 指向 new 所產生之新物件
舉例:
var x = 2;
function test() {
this.x = 1;
}
var o = new test();
alert(o.x); //1
alert(x); //2
先想想在 jQuery 中,若要讓 #button 這個元素被 click 的時候,內容改為 “Clicked” 這樣的字串,程式碼如下:
$("#button").click(function(){
this.html("Clicked");
})
此時這個 this 就是指向 $("#button") 這個物件。這樣的方式在網頁上確實很常見到。
var x = 10;
var obj = {
x: 20,
f: function(){
console.log(this.x);
var foo = function(){ console.log(this.x); }
foo(); // (2)
}
};
obj.f(); // (1)
//Ans: 20 10
- (1): obj.f() 調用時,f 前面物件為 obj,故 f 內的 this 指向 obj。
- (2):調用 foo() 時,調用的前方並未有物件,故 foo 內的 this 指向全域物件,所以輸出會是全域變數的 x 的值。
若要讓 foo 內使用 obj.x 的值,解法如下:
var x = 10;
var obj = {
x: 20,
f: function(){
console.log(this.x);
var that = this; //使用 that 保留在這個函式內的 this
var foo = function(){ console.log(that.x); } //使用 that 取得 obj
foo();
}
};
obj.f();
//Ans: 20 20
var x = 10;
var obj = {
x: 20,
f: function(){ console.log(this.x); }
};
obj.f(); // (1)
var fOut = obj.f;
fOut(); //(2)
var obj2 = {
x: 30,
f: obj.f
}
obj2.f(); // (3)
//Ans: 20 10 30
- (1):調用 obj.f() 時,此時 this 指到 obj,所以輸出為 20。
- (2):調用 fOut() 時,因為 fOut() 前面沒有任何物件,所以指向全域物件,故輸出為 10。
- (3):調用 obj2.f() 時,因為調用者為 obj2,故輸出為 30。
Reference
- https://software.intel.com/zh-cn/blogs/2013/10/09/javascript-this
- http://www.ruanyifeng.com/blog/2010/04/using_this_keyword_in_javascript.html