Inside CoffeeScript:语法强大

第一次听说CoffeeScript是Rails 3.1将它作为默认的支持,第二次深入的理解是Nodejs的兴起,CoffeeScript用它独特的语法样式,使我这个面向对象出身的程序员在写JavaScript时找到了似曾相识的感觉。当然如果对它的理解仅仅停留在语法的简化,那么只能说对JS(The World’s Most Misunderstood Programming Language)本身并不熟悉。

<< JavaScript语言精粹 >>一书中提交了很多JS本身语法存在的缺陷,例如全局变量,分号自动补全,==等。CoffeeScript的golden rule是“It’s just JavaScript”, 但是它如何避免这些陷阱,则从另一方面体现了它的强大。本文将从语法强大方面来举例分析。 1)函数默认参数 + 字符串连接

1
2
3
4
5
6
7
favorite = function(language){
  if(language == null){
    language = 'CoffeeScript';
  }
  console.log("I love " + language + " best");
}
favorite()
1
favorite = (language = 'CoffeeScript') -> console.log "I love #{language} best"

2)可变参数Splats

这样一个例子:足球赛事中,一般的排名是,冠军,亚军,和其他球队,这里再复杂一点,加上最后一名。也就是:

1
2
3
4
5
6
7
8
9
10
Given

allTeams = ['Chelsea', 'Bayern', 'Barcelona', 'Real Madrid', 'Milan', 'Inter', 'HengDa']

Output:

champaion: Chelsea
runner-up: Bayern
others:Barcelona, Real Madrid, Milan, Inter
last:HengDa

用JS和CoffeeScript分别实现

1
2
3
4
5
6
7
8
9
10
11
12
13
var allTeams = ['Chelsea', 'Bayern', 'Barcelona', 'Real Madrid', 'Milan', 'Inter', 'HengDa'];
order = function(teams) {
  var champion = teams[0];
  var runnerup = teams[1];
  var others = teams.length >= 3 ? teams.slice(2, teams.length - 1) : [];
  var last = teams[teams.length - 1];
  console.log("Champion is " + champion);
  console.log("Runnerup is " + runnerup);
  console.log("others are " + others);
  console.log("last is " + last);
};

order(allTeams);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
allTeams = [
  'Chelsea'
  'Bayern'
  'Barcelona'
  'Real Madrid'
  'Milan'
  'Inter'
  'HengDa'
]

order = (champion, runnerup, others..., last) ->
  console.log "Champion is #{champion}"
  console.log "Runnerup is #{runnerup}"
  console.log "others are #{others}"
  console.log "last is #{last}"

order allTeams...

3)Destructing Assignment

在Ruby中有同样的语法,下面的例子实现了Fibonacci数列

1
2
3
4
5
6
7
8
#Fibonacci
[last, current] = [0,1]

for i in [0..10]
  console.log last
  [last, current] = [current, current + last] 

console.log last

更加强大的是当右侧是一个对象时,会根据该对象的属性进行赋值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Shape
  constructor: (@width) ->
  computeArea: -> throw new Error('I am an abstract class!')
class Square extends Shape
  computeArea: -> Math.pow @width, 2
class Circle extends Shape
  radius: -> @width / 2
  computeArea: -> Math.PI * Math.pow @radius(), 2

#The instanceof operator tests presence of constructor.prototype in object prototype chain.
showArea = (shape) ->
  unless shape instanceof Shape
    throw new Error('showArea requires a Shape instance!') 
  console.log shape.computeArea()

showArea new Square(2) # 4 
showArea new Circle(2) # pi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
myRect =
  x: 100
  y: 200

{x: myX, y: myY} = myRect

#定义了myX和myY两个变量,并调用myRect.x和myRect.y分别赋值
console.log myX
console.log myY

#当定义的变量名称与右侧对象的key值相同时,可以更精简为
{x, y} = myRect
console.log x
console.log y

4)class与inheritance 定义了class与extends来是语法来包装JS使其更加类似面向对象的语言。给个简单例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Shape
  constructor: (@width) ->
  computeArea: -> throw new Error('I am an abstract class!')
class Square extends Shape
  computeArea: -> Math.pow @width, 2
class Circle extends Shape
  radius: -> @width / 2
  computeArea: -> Math.PI * Math.pow @radius(), 2

#The instanceof operator tests presence of constructor.prototype in object prototype chain.
showArea = (shape) ->
  unless shape instanceof Shape
    throw new Error('showArea requires a Shape instance!') 
  console.log shape.computeArea()

showArea new Square(2) # 4 
showArea new Circle(2) # pi
comments powered by Disqus