不知道各位在用CoffeeScript的 -> (dash rocket)在寫function的時候,有沒有發現有另一個長得跟它有點像,但比較胖一點的 => (fat arrow),在CoffeeScript的source code裡有一段這樣的簡短說明:
CoffeeScript has two different symbols for functions. -> is for ordinary functions, and => is for functions bound to the current value of this.
在CoffeeScript裡,用 -> 會產生一個Anonymous function,例如:
1 2 3 4 | |
編譯出來的結果是:
1 2 3 4 5 | |
執行結果是:
hello, I'm skinny eddie
而 => 也是會產生Anonymous function:
1 2 3 4 | |
執行結果是:
hello, I'm fatty eddie
就以程式的執行結果來看,用 -> 跟用 => 似乎沒什麼兩樣,但看一下用 => 編譯出來的Javascript程式碼:
1 2 3 4 5 | |
編出了看起來有點複雜的東東西,這串程式碼裡面看起來比較複雜的大概就是那個fn.apply(),我們先來看看那是做什麼的。
function.call() v.s function.apply()
直接來看段程式碼:
1 2 3 4 5 6 | |
這光用我們的人腦執行就猜得到結果是Eddie,如果我們再改一下:
1 2 3 4 5 6 | |
多了個this,但執行的結果還是一樣。這裡的this.who其實指的就是整個global的那個who,所以印出來結果也一樣。再來加一點變化:
1 2 3 4 5 6 7 8 9 | |
其實this指的對像會隨著不同的情境而有所變化。例如我們平常可能會說:「媽! 我在這裡」,如果你是在公司說這句話,「這裡」表示的是公司;如果你是在家裡說這句話,「這裡」表示的是家裡。
再回來看程式碼,在上面程式碼的第8行的呼叫指的this是整個global,在這邊就是window,而第9行指的this則是透過call()方法傳進去的那個物件,程式碼所在的情境變了,所以當第5行要印出this.who的時候,會印出the real doctor。
其實通常沒特別指定的變數或function呼叫,前面的this是可以省略的,所以上面的第8行的doctor()也可以改寫成:
1
| |
執行結果是一樣的。再來繼續再加點變化,call()還可以傳更多的參數進去:
1 2 3 4 5 6 7 8 9 10 | |
另外,在JavaScript裡,還有一個跟call()有點像的function叫做apply(),這兩個的功能差不多,最大的差別是apply()傳的第二個參數是陣列,而call()的參數則是一個一個傳進去,並用逗號分開:
1 2 3 4 5 6 7 8 9 10 | |
大概知道在JavaScript裡call()跟apply()的意思之後,再回來看我們剛剛那段CoffeeScript編譯出來的程式碼:
1 2 3 4 5 | |
function一層包一層,return再return,不過大意就是把this當做參數傳進fatty這個function裡的意思。
什麼時候會用到
有點離題了..再回來看看CoffeeScript,原來,=>在定義function的同時,還會把this也同時給綁到這個function,雖然this會隨著所在的情境而有所改變,但=>把this給綁進來之後,可以確保在指向this的時候不會指錯人。
為什麼要這樣做? 什麼時候會用到它? 大多是被拿來當做event callback的時候會用得上,來看個範例:
1 2 3 4 5 6 7 8 | |
我把eddie.say_hello傳給click做為callback,意思就是當頁面上某個id叫做student_1的元素被點擊之後,就會去執行它,而執行結果是:
Hello, my name is Eddie
但是如果你把第3行程式碼的=>換成->的話,執行結果會變成:
Hello, my name is undefined
為什麼結果是undefined? 前面提到,this會隨著出現在不同的地方而會有不同的意思,如果你是用->的話,它的this是指向你剛剛點擊的那顆按鈕,而當然那顆按鈕上面不會有username這個屬性,所以印出undefined;如果是用=>的話,它會透過fn.apply()把this給包進來,所以say_hello裡的this,指的就是它自己這個物件,也就是Student類別產生出來的instance,印出來的結果就是你要的了。
細節可以再看看它編譯出來的JavaScript code,大概就可以知道->跟=>各別做什麼不同的事。
以上,供大家參考,如果有哪邊寫錯再請跟我說 :)