Blackbing Playground

What is "this" in Javascript(上)

很多人搞不懂Javascript的「this」這個關鍵字,或者是覺得懂,但是有些地方的this又覺得怪怪的。看過一些this的教學,我覺得都講得太複雜了,其實「this」只有一個重點而已。

this永遠指向「被執行時的作用域

蝦毁??被執行?作用域??沒關係,試著把自己當作是編譯器,只要你不會在自己所撰寫的程式中迷路,其實this一點都不難區分。讓我們來看幾個例子:

1
2
3
4
5
var t = this;console.log(t); //window
function whatIsThis(){
console.log(this);
}
whatIsThis(); //window

變數t指向this,作用域在window底下,因此this指向window,這沒有問題,function whatIsThis裡頭印出的this指向誰?別會錯意囉,this永遠指向被「誰」呼叫,這個function是在window的作用域下被呼叫的,因此指向window,同理,我們來看下個例子:

1
2
3
4
function wrapper(){
whatIsThis();
}
wrapper(); //window

什麼?我是透過wrapper這個function來呼叫whatIsThis的,為什麼還是window?請想想wrapper的作用域是誰?是 window,window呼叫wrapper,this還是指向window,作用域並沒有改變,這時呼叫whatIsThis當然作用域還是沒有改變,依然指向window。

接下來結合其他的型態:

1
2
3
var arr = [this, 1, 2, function(){console.log(this)}];
console.log(arr[0]); //window
arr[3](); //arr

arr[0]指向window,原因是arr這個陣列被宣告時作用域是在window底下的,因此arr[0]是指向this。而arr[3]呢?當他被執行時,this被closure的方式被保存在function裡頭,因此呼叫arr[3]時,this指向他當時的作用域,也就是arr,看起來有點複雜,不過只要把自己想程式編譯器,問自己this何時被執行就好了。 Object跟Array一樣,其實大部分應該會更常在Object裡頭來使用this,我們來看一個比較實用的例子:

1
2
3
4
5
6
var box = {
length:100,
width: 300,
area: this.length* this.width
};
console.log(box.area);

看起來蠻合邏輯的一段程式,猜猜看,box.area是什麼?答案是NaN。Why?因為this根本就不是指向box,哪來的 this.length、this.width。剛說過this永遠指向「被執行的作用域」,box物件在宣告時,屬性volumn被指派時,this當然是指向window,所以這個邏輯是錯的。那怎辦?很多人遇到這個問題時,「那就不要使用this吧!」所以程式變成

1
2
3
4
5
6
var box = {
length:100,
width: 300,
area: box.length* box.width
};
console.log(box.area);

OK!box.area很正確的被計算出來了,但是這是個好辦法嗎?假如今天程式變成

1
2
3
4
5
6
7
8
var box = {
length:100,
width: 300,
area: box.length* box.width,
volumn: box.length* box.width * box.height,
height:50
};
console.log('box.volumn='+box.volumn);

再猜猜看,box.volumn的值是什麼?答案是…..NaN,因為box在被宣告時,volumn屬性決定前尚未宣告height,導致 box.height變成undefined。「那就把height提前宣告就好啦?」等等,這樣真是不求甚解。這樣的需求用this的特性來取得是很直覺的事情,應該要想辦法搞定的。

1
2
3
4
5
6
7
8
var box = {
length:100,
width: 300,
getArea: function(){ return this.length* this.width},
getVolumn: function(){ return this.length* this.width*this.height},
height:50
};
console.log('box.volumn='+box.getVolumn());

如上,用getArea的function來動態取得box的長寬高,box.getVolumn function裡頭的this便是指向box這個物件,因為getVolumn被呼叫時,作用域就在box,所以this指向box。 this跟幾個重要型態的關係大概就是這樣,萬變不離其宗,在任何型態裡頭使用this都是照這個思維去走即可。下一篇會再介紹new Object之後的this以及與window事件交互作用之後的this。