高見龍

iOS app/Ruby/Rails Developer & Instructor, 喜愛非主流的新玩具 :)

CoffeeScript 使用篇

CoffeeScript裝好了,準備來泡咖啡了

假設我寫了一個檔名為app.coffee(內容怎麼寫請見CoffeeScript基礎篇),現在我想來編譯這個coffee檔:

> coffee --watch --compile app.coffee

這行指令會把app.coffee編譯產生一個同名的app.js

加上了–watch參數,CoffeeScript的編譯器會一直監看這個檔案,只要檔案一有變動,編譯器就會再重新編譯產生一份新的.js檔案。如果你覺得–watch、–compile太囉嗦或不想打那麼多字,也可以用-w、-c來替代。

如果你希望把幾個coffee檔案在編譯的時候合併成一個.js檔,以減少http request的數量,你可以這樣做:

> coffee --join application.js --compile *.coffee

這樣就會把同一個目錄裡的coffee檔編譯並組合成同一個js檔,這裡–join也可以簡寫成-j。

更多內容請見coffee –help

CoffeeScript Console

CoffeeScript也有像Ruby的irb一樣的REPL,提供一個像shell的互動介面可以讓你試玩,你只要不帶參數的執行CoffeeScript編譯器:

> coffee
coffee> name = "eddie"
'eddie'

這樣你就可以在這個環境裡面試一些語法。如果你曾經使用過Ruby的irb,你對這個結果應該不陌生。

一定要編譯成js檔嗎?

上面講的是如何把coffee檔編譯成js檔,編譯成js檔當然放到網頁上當然沒問題,但是不是一定要編譯呢? 不編譯的話,coffee檔能不能直接拿來用?

當然是可以的,只要先引入一行CoffeeScript的編譯器,就可以在HTML的頁面裡直接寫CoffeeScript:

1
<script type="text/javascript" src="http://jashkenas.github.com/coffee-script/extras/coffee-script.js"></script>

然後你要這樣寫:

1
2
3
<script type="text/coffeescript">
  alert 'test'
</script>

或是寫在外部檔案:

1
<script type="text/coffeescript" src="myapp.coffee"></script>

都可以,這樣就能讓你的瀏覽器就看得懂CoffeeScript,只是這樣一來的速度一定比直接編譯成.js檔要來得慢,所以實務上還是會先編譯成.js檔再拿來使用。

OK! 可以開始喝咖啡了!

CoffeeScript 安裝篇

要安裝CoffeeScript的話,會需要先安裝Node.js以及Node.js的套件管理工具 – npm (Node Package Manager)

說明:

以下將會以Mac及Ubuntu為主要的平台,Windows就對不起了,我沒有機器可以測試..在安裝過程中如果出現權限不足的錯誤訊息,請使用sudo暫時取得安裝的權限。

安裝Node.js

官網:http://nodejs.org/

> git clone git://github.com/joyent/node.git
> cd node
> ./configure
> make
> sudo make install

更多細節請參考:https://github.com/joyent/node/wiki/Installation

安裝npm

官網:http://npmjs.org/

> curl http://npmjs.org/install.sh | sh

一行搞定!(如果你沒有curl的話請另外安裝)

安裝CoffeeScript

如果你的Node.js以及npm都順利安裝完成的話,接下來,在安裝之前先更新一下npm的套件資訊(不一定更新,只是確保npm會幫你裝最新的套件版本):

> npm update
npm info it worked if it ends with ok
npm info using npm@0.3.18
npm info using node@v0.4.10
npm WARN Invalid range in engines.node.  Please see `npm help json` ~v0.4.9
npm WARN Invalid range in engines.node.  Please see `npm help json` v0.4.8~v0.4.9
npm info outdated Everything up-to-date.
npm info update Nothing to update
npm ok

再來安裝CoffeeScript:

> npm install coffee-script
npm info it worked if it ends with ok
npm info using npm@0.3.18
npm info using node@v0.4.10
npm info preinstall coffee-script@1.1.1
npm info install coffee-script@1.1.1
npm info postinstall coffee-script@1.1.1
npm info preactivate coffee-script@1.1.1
npm info activate coffee-script@1.1.1
npm info postactivate coffee-script@1.1.1
npm info build Success: coffee-script@1.1.1
npm ok

其實如果你是Mac的使用者的話,上面這些動作可以直接用homebrew一行搞定,超幸福的:

> brew install coffee-script

homebrew會幫你把需要的東西一起處理好(誠心推薦,不要再用ports了)。如果你發現用homebrew安裝的CoffeeScript不是最新版本的話,請先用brew update指令,更新一下homebrew的fomula再重新安裝即可。

看看有沒裝好:

> coffee -v
CoffeeScript version 1.1.1

就這樣,可以準備開工了!

補充:

在 Windows 上可以用這個 https://github.com/alisey/CoffeeScript-Compiler-for-Windows

在 NetBeans 上可以用這個 https://github.com/dstepanov/coffeescript-netbeans (注意, Windows 7 要用 0.9.1 版才不會有問題)

感謝jace補充 :)

CoffeeScript 簡介

什麼是CoffeeScript?

簡單的說,它就是JavaScript啦,只是用不同的程式語言來寫而已。

為什麼選擇CoffeeScript?

不少JavaScript社群,包括JavaScript的老爸Brendan Eich,也對它讚譽有加,有社群及大神的背書,加上Rails 3.1之後會把CoffeeScript變成預設支援,是我選擇它的原因之一。不過對我個人來說,CoffeeScript的語法感覺像是PythonRuby的混合體,從這些語言身上借了一些我個人很愛的元素,加上對我個人來說學習的負擔不算太大,這才是我選擇它最主要的原因(聽說CoffeeScript還有向Haskell取經,不過我跟它不熟)。

從Python借來的:

  • 使用縮排(identation)來取代大括號,這一直是我的菜,我有程式碼潔癖!
  • 簡單好用的List Comprehension語法,在CoffeeScript也可以用(雖然用起來有那麼一點點不太一樣)。

從Ruby借來的:

  • 有if modifier可以用,可以把if寫在句子後面,也有unless可以用。
  • 在呼叫方法以及邏輯判斷的時候,可以視情況省略小括號。
  • 每行行尾不用分號(其實Python也是)。
  • 不用特別寫return,最後的執行結果就是回傳值。
  • 有類似irb的console介面模式可以用。

優缺點

好處?

  • 程式碼會變短,變得容易閱讀,也更容易抓出問題來,即使是以OOP的方式來寫js,語法看起來也是相當清楚。
  • 經過CoffeeScript編譯出來的JavaScript,因為它在編譯的時候有做最佳化,而且這些最佳化可能是我們這種小兵不知道的技巧,某些情況下的編譯出來的效能可能比我們一般手寫的要來得好。
  • 不會有因為變數scope而混淆程式語意或造成或memory leak的問題。
  • 編出來的js檔丟給JSLint檢查不會跳出一堆抱怨。

缺點?

  • 你可能得再花時間再熟悉一門程式語言,不過如果你本來就熟悉Python或Ruby的話,其實負擔並不大,而且老實說Python/Ruby也沒很難學。

FAQ

Q: 學CoffeeScript就可以取代一般的JavaScript嗎?

A: 也許可以取代,但這不代表你就不用學JavaScript,如果你並不熟悉JavaScript是怎麼一回事,你應該也不知道你要拿CoffeeScript來取代什麼東西。最一開始也提到,CoffeeScript就只是JavaScript而已,所以原本該花時間在學習JavaScript的,不會因為CoffeeScript而省下來的。

Q: CoffeeScript聽說要編譯成*.js檔才能用?

A: 是的。但如果你不想編譯,透過在瀏覽器裡直接引入compiler也可以讓瀏覽器看得懂*.coffee,只是通常實務上還是會把編成*.js檔。BTW, CoffeeScript的compiler本身也是用CoffeeScript寫的,自己寫自己,這點光是聽起來就很酷。

Q: 改用CoffeeScript的話,是不是之前寫的JavaScript都得整個打掉重寫?

A: 也不用啦,CoffeeScript的目的並不是取代原來的JavaScript,而是用更簡單、清楚的語法來寫JavaScript,所以原來寫好的就留著吧,除非你也覺得寫得不好,加上手癢想練功。而且如果你想在CoffeeScript裡直接使用一般JavaScript的語法也是ok的,CoffeeScript可以讓你把一般的JavaScript語法embed在CoffeeScript裡。

Q: CoffeeScript可以把.coffee檔編譯成.js檔,那也有工具可以把js檔轉成coffee檔的嗎?

A: 有的,有個工具叫做js2coffee,你可以在線上玩看看,也可以透過npm安裝到你的電腦裡。

Q: 有開發工具嗎?

A: CoffeeScript的官網有列了一些工具供參考。不過寫CoffeeScript只要一般的文字編輯器就行了,如果你沒有特別偏好的文字編輯器,我推薦你使用vim,它是個免費又功能強大的文字編輯器,投資時間學一下它保證不會後悔的。vim有一堆很威的plugin可以用,我從pct那邊fork了他的vim設定,也把CoffeeScript的外掛加上去了 https://github.com/kaochenlong/pct.vim (PS: 其實pct的版本就有加上這功能了..)

如果你是用Textmate,恭喜你CoffeeScript的作者有放出了個方便的bundle可以用。除了一些方便的snippet以及程式碼顏色亮度之外,還可以讓你很簡單的執行/檢視你的coffee檔到時候編譯成js檔的樣子。

Microsoft的Visual Studio 2010最近也有一個免費的web workbench套件可以用,讓VS也開始支援SassLess以及CoffeeScript

Q: 有書可以參考嗎?

A: 在這個當下,剛好有一本”CoffeeScript: Accelerated JavaScript Development“,不過我想官網的資料相當完整,看完你就差不多知道怎麼用了。

另外還有一些不錯的學習資源:

Public, Protected and Private Method in Ruby

如果你曾經在別的程式語言寫過OOP,你也許對類別的方法存取限制不會太陌生。類別的方法的存取限制常見的有三種:public、protected以及private。

這三種存取限制,比較常聽到的解釋大概會是像這樣:

“public就是所有的人都可以直接存取,private是只有在類別內部才可以存取;而protected差不多是在這兩者之間,比private寬鬆一些,但又沒有public那麼自在,protected在同一個類別內或是同一個package,或是繼承它的子類別可以自由取用,但如果不是的話則不可存取。”

Ruby也有類似的方法存取限制,為什麼特別說「類似」,前面又為什麼需要特別提「大家常聽到的解釋」,因為Ruby在這部份的實作是不太一樣的,待會後面會再詳細說明。

怎麼做?

先來看看怎麼寫,Ruby的方法存取限制有兩種寫法,一種是寫在方法定義之前:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Father

  def method_a
      puts "I am METHOD A in #{self.class}"
  end

  def method_b
      puts "I am METHOD B in #{self.class}"
  end

  protected
  def method_c
      puts "I am METHOD C in #{self.class}"
  end

  private
  def method_secret
      puts "I am spider man in #{self.class}"
  end

end

在Ruby的類別裡,方法只要沒有特別限制預設就是publilc的,除了一個例外,就是initialize方法,它永遠是private的,只會被new方法呼叫。

把存取控制放在前面的這種寫法,只要在它設定之後的方法定義都會受影響,除非又遇到另一個存取控制的設定。在上面的這段程式碼,method_a跟method_b沒有特別限制,所以是public方法(如果你想要特別加上public也沒問題,只是通常不會這麼做),method_c是protected方法,而method_secret則是屬於private方法。

另一種的方法存取限制是寫在方法定義之後:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Father

  def method_a
      puts "I am METHOD A in #{self.class}"
  end

  def method_b
      puts "I am METHOD B in #{self.class}"
  end

  def method_c
      puts "I am METHOD C in #{self.class}"
  end

  def method_secret
      puts "I am spider man in #{self.class}"
  end

  protected :method_c
  private :method_secret

end

哪種比較好?

這兩種寫法哪種方法比較好? 都好,隨個人喜好。我個人喜好第一種,因為我習慣會先把public的方法放在類別的上半部,而把private方法放在類別的最底下,所以使用第一種寫法對我來說寫起來比較順手。

其實public、protected以及private這三個在Ruby裡並不是關鍵字,它也只是Ruby裡的方法而已。

哪裡不一樣?

前面為什麼會特別提到Ruby的方法存取限制跟其它的程式語言「類似」呢? 雖然Ruby裡的確也有public、protected以及private,但事實上是不太一樣的,特別是private方法。我們先來看一小段的程式碼:

1
2
3
4
5
father = Father.new
father.method_a        # I am METHOD A in Father
father.method_b        # I am METHOD B in Father
father.method_c        # NoMethodError
father.method_secret   # NoMethodError

father是Father類別生出來的實體,而實體的public方法如所預期的印出結果,protected跟private方法呼叫的時候產生NoMethodError的例外,看起來很正常,那到底是哪邊不太一樣?

我們再來做個叫做Son的子類別,繼承自Father類別:

1
2
3
4
5
6
7
8
9
10
11
class Son < Father

  def son_method_c
      method_c
  end

  def son_method_secret
      method_secret
  end

end

我給Son類別加了兩個方法,分別會呼叫Father類別的protected跟private方法,再來看範例:

1
2
3
4
5
6
7
son = Son.new
son.method_a           # I am METHOD A in Son
son.method_b           # I am METHOD B in Son
son.method_c           # NoMethodError
son.method_secret      # NoMethodError
son.son_method_c       # I am METHOD C in Son
son.son_method_secret  # I am spider man in Son

在子類別呼叫父類別的protected方法,這不是新鮮事,但你注意到了嗎? 在子類別裡可以直呼叫父類別的private方法耶!

先來看這行:

1
son.method_a

一般我們會把這行翻譯成:

“有一個物件叫做son,然後呼叫了son物件的method_a方法”

不過如果你曾經認識過Smalltalk或是Objective-C的話,你會發現他們會把這行翻譯成:

“有一個接收者(receiver)叫做son,然後對著這個recevier送了一個叫做method_a的訊息(message)”

為什麼特別提這個? 因為在Ruby裡的private方法,只要沒有明確的指出recevier的話就都可以呼叫。所以在上面例子裡的Son類別,即使是呼叫父類別的private方法,只要不要有recevier,它就不會有錯誤產生。

也就是因為這樣,在Ruby的private方法其實不只類別自己內部可以存取,它的子類別也可以。再來看一下這段程式碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A

  def a
      self.b
  end

  private
  def b
      puts "Hello, This is Private B!"
  end

end

the_a = A.new
the_a.a        # NoMethodError

在A類別的a方法呼叫類別內部的b方法,看起來很合理吧,但實際執行就會出錯NoMethodError的例外,說你存取到了private方法了!! 為什麼? 因為你在呼叫方法b的時候加上了self,前面有提到”在呼叫Ruby的private方法時,不能明確的指定recevier”,在這裡卻明確的指出了self,所以出現錯誤訊息了。沒錯,連self也不行。

我們很常用的puts方法,它就是Object這個類別的private方法之一(更正確的說,是Kernel模組mixin到Object類別裡的方法)。我們平常會這樣用:

1
puts "Hello Ruby"

但如果你這樣做:

1
self.puts "Hello Ruby"

就會跳出NoMethodError

Protected方法?

那protected方法呢? 它的規定就沒那麼嚴格了,你要指定或不指定recevier都可以;至於public方法,就跟其它語言的定義差不多,隨便你用啦。

真的這麼private?

不過,其實Ruby的private方法也不是真的那麼private,轉個彎,一樣可以被外部呼叫:

1
2
3
father = Father.new
father.method_secret          # 是我們預期的 NoMethodError 沒錯
father.send(:method_secret)   # I am spider man in Father

前面提到的puts其實也可以改寫成:

1
Object.send(:puts, "Hello Ruby")  # Hello Ruby

這..這樣會不會有點扯? 如果連private都能被直接存取,那當初何必還要這樣設計呢? 還是直接乾脆全部都public就好了?

我想這其實是Ruby當初設計的哲學之一,Ruby把很大部份的權利都下放給程式設計師,讓開發者有最大的彈性空間可以運用(或惡搞),也就是這樣,在Ruby做Metaprogramming是相對的比在別的程式語言容易的。不只在這裡,你應該還可以在很多地方看到這個Ruby的專屬特性。

僅供參考

如果說這些存取限制只是”參考用”,那到底什麼時候會用到?

雖然說它只是”參考用”,我個人還是會把它當做是程式碼的寫作準則。雖然你可以透過send方法來存取private方法,但不代表你就應該這樣做。而且它也不是真的那麼沒有用,像是在寫Rails的時候,Controller裡的Action預設都是public的,如果你的routes.rb如果把路徑的對應全部打開,那所有的Action都有可能透過網址而被存取到,那也許不會是你想要的結果。

Flashers on Google+

image

來勢洶洶的Google+,有人一用了就決定搬家了,有人覺得還好,沒多好用。Google+會不會讓社群網站的版圖重新洗牌呢? 我沒有預言的特異功能,這就留給時間來證明了。

不過的確是有一些國內外的Flasher/ASer也上去註冊了帳號,至於本人是不是真的會搬過來經營,還是留在原本的Twitter/Facebook,這就看個人喜好了。

以下列出了一些我目前在Google+上有看到的Flasher,如果有興趣可以參考看看。我列出來的名單有的是常見面、常聊天的朋友,有的是AS讀書會的朋友,有的是工作上有合作,有的只有在網路上交流過。沒列出來的不代表就不是高手,而是小的我人面不夠廣,認識的人實在不多,或是還沒有這個緣份能認識到這些高手,所以這個名單歡迎大家來補充。

先聲明一下,列這個名單的心態,只是單純的想讓更多的朋友能認識更多的Flasher,也許能透過社群網站知道這些高手們最近在研究什麼心得,或是有新的徵才資訊,或是有案仔要找這些人合作.. 其實很單純的。不過如果有不希望被列出來的也請跟我說,我會馬上處理。

提醒

提醒大家一下,在網路上發言、加好友請記得遵守網路禮儀,特別是Google+的社交圈的規則跟Facebook/Twitter/Plurk是不太一樣的,加了對方之後,即使對方沒把你加入他的社交圈,他還是可能得看到你發表的訊息,這點請多留意。

以下名單依英文字母先後排序,並且可能隨時會更新,最後更新日期:2011/7/21

國外

國內

最後,如果大家不嫌棄,這是小的我自己的

http://www.eddie.com.tw/+ SHAMELESS PROMOTION!!

我想這個名單並沒辦法包括所有的Flasher,我相信還有許多業內的高手是我還沒福份認識到的,至少日本跟大陸的那邊的神人們我還沒機會遇到。以上,如果不希望被列出來的,請跟我說,我會馬上拿下來;如果有知道漏了誰的,或是只是單純的想交朋友的,也歡迎在底下留言補充囉。