CoffeeScript快速入门

CoffeeScript快速入门

CoffeeScript是最近比较流行的一个小的编程语言,它有自己的语法(受Python和Ruby影响比较多,个人觉得更象Ruby),其编译器将其编译输出javascript。至于生成的javascript则可以在浏览器运行也可以在服务器端运行(NodeJS)。例如最简单的helloWorld函数(你可以点击这个链接进入CoffeeScript提供的在线工具)

# ===========
# CoffeeScript
# ===========
helloWorld = (name)->
  alert "Hello World #{name}"

// ==========
// Javascript
// ==========
var helloWorld;

helloWorld = function(name) {
  return alert("Hello World " + name);
};

下面我们可以就上面的代码简单介绍CoffeeScript的语法。

简单语法

  1. 空格/缩进很重要

    跟Ruby一样,没有分号作为语句的分隔符,而是以换行;也没有花括号来表示一个语句块,而是以缩进来表示。所以在上面的代码中alert语句是缩进了两个空格。当然你可以缩进三个,四个,任意个,只是同一个语句块要有同样的缩进。

  2. 变量不需要声明

    所有的变量都会自动定义成局部变量,以消除全局变量。例如上面例子的helloWorld函数。熟悉javascript的都知道,没有var声明的变量,自动成为全局变量,那样容易造成变量名的混乱。而不声明var是可能发生的手误,尤其对于新手来说。所以如果想要定义全局变量,习惯上可能会以g_作为前缀,这样便于代码的阅读和维护。当然现在的Javascript讲究的是尽量不要用全局变量,最大的理由就是变量的覆盖,尤其是在采用了很多类库的情况下,如果大家都用全局变量就完蛋了。举个例子来说,大家都知道大名鼎鼎的$,JQuery的简写。如果我自己的代码也定义一个全局变量为$,并且加载在jQuery之后,那么就覆盖了jQuery的$,你再想用它就不是jQuery了。

  3. 函数声明采用箭头(->)

    究其原因是没有的,反正语法就是这么规定,所以需要记住。类似与上面的例子,在箭头后面我们定义了函数的实现。至于函数的参数需要在箭头的左边声明,并且置于括号之中。如果没有参数的话,你可以在括号中置空,也可以连括号都不要。CoffeeScript支持设置默认参数,可变参数,具体可以参考CoffeeScript

  4. 函数调用可以不要括号

    你可以看到alert函数调用是没有加括号的,这也是Ruby里面的习惯用法。这样更佳符合英文的书写和阅读,对于我们中国人来说可能有括号更加容易理解,至少象我这样从C语言过来的。但是要注意,如果一个函数没有参数的话,那么调用的时候一定要加括号,应为CoffeeScript它不确定你是当当要引用这个函数还是要调用它。其实Ruby是默认认为调用。这里也可以看到CoffeeScript只是实现了Javascript的一个子集,因为它也可以调用alert方法。

  5. 双引号的字符串中可插值

    在调用alert时候生成的字符串,我们直接在字符串中引入了变量name。这个方法还是很不错的。注意一定是双引号的字符串,单引号是不行的。

  6. 函数返回值默认是最后一句的值

    在生成的javascript版本helloWorld,你可以发现有return语句,尽管我们在CoffeeScript中并没有return。这就是默认的,CoffeeScript函数返回最后一句的值。有的时候这减少了写return了。但是如果在函数中间要返回值,那还是得要return的。

class

其实我最喜欢的是类的支持。jQuery这么流行的库为什么不支持面向对象呢?我认为基本的面向对象就是类,类的继承,方法的覆盖。这些CoffeeScript都给出了很好的支持。譬如,

class Animal
  @count: 0
  @getCount: ->
    @count

  constructor: (@name)->    
    Animal.count++
  getName: ->
    @name

  say: ->
    alert @getName()

class Dog extends Animal
  constructor: (name)->
    super(name)
    @type = 'Dog'

  getName: ->
    @type + ": " + super()

animal = new Animal('A')
# alert('A')
animal.say()
# 1
alert Animal.getCount()

# alert('Dog: D')
dog = new Dog('D')
dog.say()
# 2
alert Animal.getCount()

# 0
alert Dog.getCount()

# error, no method getCount for animal
alert animal.getCount()
# error, no method getCount for dog
alert dog.getCount()

对应输出的Javascript则是

    var Animal, Dog, animal, dog,
  __hasProp = {}.hasOwnProperty,
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

Animal = (function() {

  Animal.count = 0;

  Animal.getCount = function() {
    return this.count;
  };

  function Animal(name) {
    this.name = name;
    Animal.count++;
  }

  Animal.prototype.getName = function() {
    return this.name;
  };

  Animal.prototype.say = function() {
    return alert(this.getName());
  };

  return Animal;

})();

Dog = (function(_super) {

  __extends(Dog, _super);

  function Dog(name) {
    Dog.__super__.constructor.call(this, name);
    this.type = 'Dog';
  }

  Dog.prototype.getName = function() {
    return this.type + ": " + Dog.__super__.getName.call(this);
  };

  return Dog;

})(Animal);

animal = new Animal('A');

animal.say();

alert(Animal.getCount());

dog = new Dog('D');

dog.say();

alert(Animal.getCount());

alert(Dog.getCount());

alert(animal.getCount());

alert(dog.getCount());

从这个代码的对比来看,CoffeeScript的确是相当高效的.具体说来class实现有如下要点

  1. 关键字class声明一个对象

    在对象内部的定义,则是采用了函数名后面加冒号(不是等号),然后再是函数的定义。

  2. constructor为构造函数 new一个对象的时候就会调用该函数,相当于Ruby中的initialize函数。显然每个class只有一个构造函数。在成员函数中的@为this的简写,例如getName函数中的@name表示就是this.name,也就是类实例的name变量。在constructor中我们采用了一个更加简单的写法,就是直接将传入的name参数赋给成员变量name,所以我们直接在参数name前面加了@符号。

  3. super 子类的方法可以通过super调用父类的方法,例如Dog的constructor和getName,都有这样的用法。

  4. 成员函数或变量声明前加@表示静态方法或变量 例如getCount和count,它们都是直接转化成Animal的属性。所以在调用getCount的时候,只有通过Animal.getCount()才起作用。通过实例animal和dog进行调用,都会报错说方法不存在。而通过Dog类调用的时候,你会发现该方法是存在的,但是值可能不是你想要的。这是因为CoffeeScript生成的 JS代码__extends会将父类的所有属性复制一份到子类,也就是说在最开始的时候会将Animal的count和getCount属性复制到Dog里面去。而我们在Animal的构造函数中,只是增加了Animal.count的计数,而不是Dog.count的计数。

CoffeeScript的负面评价

更多其它的细节可以在CoffeeScript找到。在好评如潮的情况下,我也找到一些负面的评价。如这两篇文章,

http://ryanflorence.com/2011/case-against-coffeescript/

http://ceronman.com/2012/09/17/coffeescript-less-typing-bad-readability/

我觉得写得相当不错。我是不太喜欢There is more than one way to do it (TIMTOWTDI) (不止一种方法来实现一个功能),因为这样势必造成学习曲线增加,难记,也导致难以维护。每个人用不同的方法来做,那维护的人就要痛苦死了。而Java就是因为简单所以才会有这么多人使用,开发效率也才会高,才会容易阅读和维护。

安装CoffeeScript

最后介绍一下如何在本地安装CoffeeScript,虽然在官网都有,而且也可以在官网找到在线工具,但是为了文章的完整性,在最后还是附上。

  1. 安装NodeJS
  2. npm install -g coffee-script 运行安装coffee script
  3. coffee -o lib/ -cw src/ 这个表示运行自动监控src下面的".coffee"文件,然后以相同的文件名编译输出到lib目录下面,只是文件名后缀为js。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值