CoffeeScript 是什麼?

CoffeeScript

CoffeeScript 是個能夠編譯成 JavaScript 的簡易語言。受到 Ruby、Python 與 Haskell 等語言的啟發,CoffeeScript 增強了 JavaScript 的簡潔性與可讀性。

直接來個簡單的概觀看看

賦值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 賦值:
number = 42
opposite = true

# 條件式:
number = -42 if opposite

# 函式:
square = (x) -> x * x

# 陣列:
list = [1, 2, 3, 4, 5]

# 物件:
math =
root: Math.sqrt
square: square
cube: (x) -> x * square x

# 變參:
race = (winner, runners...) ->
print winner, runners

# 空值偵測:
alert "I knew it!" if elvis?

# 陣列推導:
cubes = (math.cube num for num in list)

編譯成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// 賦值:
var cubes, list, math, num, number, opposite, race, square;

number = 42;

opposite = true;

if (opposite) {
// 條件式:
number = -42;
}

// 函式:
square = function(x) {
return x * x;
};

// 陣列:
list = [1, 2, 3, 4, 5];

// 物件:
math = {
root: Math.sqrt,
square: square,
cube: function(x) {
return x * square(x);
}
};

// 變參:
race = function(winner, ...runners) {
return print(winner, runners);
};

if (typeof elvis !== "undefined" && elvis !== null) {
// 空值偵測:
alert("I knew it!");
}

// 陣列推導:
cubes = (function() {
var i, len, results;
results = [];
for (i = 0, len = list.length; i < len; i++) {
num = list[i];
results.push(math.cube(num));
}
return results;
})();

CoffeeScript 2

在 CoffeeScript 2 中,最大的改變莫過於輸出的 JavaScript 程式碼格式(現在會輸出成較新的 ES6 或 ES2015 風格)。

而 CoffeeScript 中的 => 亦會變成 JS 中的 =>,且 CoffeeScript 的 class 也會等同於 JS 的 class 類別標籤…等。還有主要追加的新功能,像是:非同步函式和 JSX。

非同步函式

ES2017 的非同步函式現在能夠透過 await 關鍵字進行使用,不需要額外使用 async,使得非同步函式在 CoffeeScript 中寫起來就像一般的函式。

yield return 可以強迫函式成為一個產生器函式,而 await return 則能夠強迫讓一個函式成為非同步函式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
new Promise (resolve) ->
window.setTimeout resolve, ms

say = (text) ->
window.speechSynthesis.cancel()
window.speechSynthesis.speak new SpeechSynthesisUtterance text

countdown = (seconds) ->
for i in [seconds..1]
say i
await sleep 1000 # 等個一秒
say "Blastoff!"

countdown 3

編譯成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var countdown, say, sleep;

sleep = function(ms) {
return new Promise(function(resolve) {
return window.setTimeout(resolve, ms);
});
};

say = function(text) {
window.speechSynthesis.cancel();
return window.speechSynthesis.speak(new SpeechSynthesisUtterance(text));
};

countdown = async function(seconds) {
var i, j, ref;
for (i = j = ref = seconds; (ref <= 1 ? j <= 1 : j >= 1); i = ref <= 1 ? ++j : --j) {
say(i);
await sleep(1000); // 等個一秒
}
return say("Blastoff!");
};

countdown(3);

JSX

JSX 是能夠帶有類 XML 元素結構的 JavaScript。雖然初期是為了 React 所設計的,但這並不是一個框架或者函式庫。

CoffeeScript 不需要任何的額外擴充套件或設定,就能夠支援類 XML 元素。XML 元素會被編譯並輸出成一般的 JSX 結果,就像 Babel 與 React JSX 的轉化。不過 CoffeeScript 並不會輸出用以呼叫 React.createElement 的函式,亦不會有任何與 React 和其他框架有關的程式碼。

就像 JSX 和 HTML 那樣,你可以使用 <> 符號。你也能在 { 和 } 標籤中使用 CoffeeScript。為了避免編譯器錯誤,當 <> 是用作「小於」或「大於」符號時,你應該透過空白來避免它們被誤認為 XML 標籤。所以你該使用 i < len 而不是 i<len

1
2
3
4
5
6
7
8
9
renderStarRating = ({ rating, maxStars }) ->
<aside title={"Rating: #{rating} of #{maxStars} stars"}>
{for wholeStar in [0...Math.floor(rating)]
<Star className="wholeStar" key={wholeStar} />}
{if rating % 1 isnt 0
<Star className="halfStar" />}
{for emptyStar in [Math.ceil(rating)...maxStars]
<Star className="emptyStar" key={emptyStar} />}
</aside>

編譯成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  var renderStarRating;

renderStarRating = function({rating, maxStars}) {
var emptyStar, wholeStar;
return <aside title={`Rating: ${rating} of ${maxStars} stars`}>
{(function() {
var i, ref, results;
results = [];
for (wholeStar = i = 0, ref = Math.floor(rating); (0 <= ref ? i < ref : i > ref); wholeStar = 0 <= ref ? ++i : --i) {
results.push(<Star className="wholeStar" key={wholeStar} />);
}
return results;
})()}
{(rating % 1 !== 0 ? <Star className="halfStar" /> : void 0)}
{(function() {
var i, ref, ref1, results;
results = [];
for (emptyStar = i = ref = Math.ceil(rating), ref1 = maxStars; (ref <= ref1 ? i < ref1 : i > ref1); emptyStar = ref <= ref1 ? ++i : --i) {
results.push(<Star className="emptyStar" key={emptyStar} />);
}
return results;
})()}
</aside>;
};