# CoffeeScript -&gt; 與 =&gt; 的差別

> 

Published: 2011-11-18
URL: https://kaochenlong.com/dash-rocket-vs-fat-arrow-in-coffeescript

---

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


