初识 CoffeeScript


很早就知道这CoffeeScript一门语言,但是一直没有机会系统的学习下,那天趁在公司没有什么要紧的项目做,就根据CoffeeScript首页的例子学了一下。

引用CoffeeScript的一段介绍:

CoffeeScript 是一门编译到 JavaScript 的小巧语言. 在 Java 般笨拙的外表下, JavaScript 其实有着一颗华丽的心脏. CoffeeScript 尝试用简洁的方式展示 JavaScript 优秀的部分.

CoffeeScript 的指导原则是: “她仅仅是 JavaScript”. 代码一一对应地编译到 JS, 不会在编译过程中进行解释. 已有的 JavaScript 类库可以无缝地和 CoffeeScript 搭配使用, 反之亦然. 编译后的代码是可读的, 且经过美化, 能在所有 JavaScript 环境中运行, 并且应该和对应手写的 JavaScript 一样快或者更快.

—- 来自CoffeeScript中文

自己是写PHP的,最开始接触CoffeeScript的时候,就被他吸引了,因为它竟然可以不用括号、分号就可以识别语法规则,在用jQuery编写一些事件的时候经常会写回调函数,常常在最后留下一大串的 });

使用CoffeeScript就可以写出很优美的Js的代码了,另外还可以很好的避免局部变量因为不加var而引用到全局变量。而造成一些莫名其妙的错误。

下面是自己的一些笔记:

一、安装

因为CoffeeScript是基于nodejs的,所以首先需要安装nodejs (这家伙也不错,居然可以让js运行在服务端),在nodejs下载相应平台的版本就可以了,我这里使用CentOS系统。

wget -c http://nodejs.org/dist/v0.10.26/node-v0.10.26.tar.gz
tar -zxvf node-v0.10.26.tar.gz -C /usr/local/src/
cd /usr/local/src/
./configure
make && make install

当安装成功了后可以使用

npm -v

测试是否安装成功~   如果没有该命令看看是不是PATH没有加入。

使用npm包管理工具安装CoffeeScript(为了加快安装速度,可以使用淘宝NPM镜像)

安装CoffeeScript

npm install -g coffee-script

确定安装成功

coffee -v
CoffeeScript Version 1.7.1

 

二、Hello World

2.1编译一个第一个coffeeScript文件

coffee命令参数:

-c, --compile 编译一个 .coffee 脚本到一个同名的 .js 文件.
-m, --map 随 JavaScript 文件一起生成 source maps. 并且在 JavaScript 里加上 sourceMappingURL 指令.
-i, --interactive 启动一个交互式的 CoffeeScript 会话用来尝试一些代码片段. 等同于执行coffee 而不加参数.
-o, --output [DIR] 将所有编译后的 JavaScript 文件写到指定文件夹. 与 --compile 或 --watch 搭配使用.
-j, --join [FILE] 编译之前, 按参数传入顺序连接所有脚本到一起, 编译后写到指定的文件. 对于编译大型项目有用.
-w, --watch 监视文件改变, 任何文件更新时重新执行命令.
-p, --print JavaScript 直接打印到 stdout 而不是写到一个文件.
-s, --stdio 将 CoffeeScript 传递到 STDIN 后从 STDOUT 获取 JavaScript. 对其他语言写的进程有好处. 比如:
cat src/cake.coffee | coffee -sc
-l, --literate 将代码作为 Literate CoffeeScript 解析. 只会在从 stdio 直接传入代码或者处理某些没有后缀的文件名需要写明这点.
-e, --eval 直接从命令行编译和打印一小段 CoffeeScript. 比如:
coffee -e "console.log num for num in [10..1]"
-b, --bare 编译到 JavaScript 时去掉顶层函数的包裹.
-t, --tokens 不对 CoffeeScript 进行解析, 仅仅进行 lex, 打印出 token stream:[IDENTIFIER square] [ASSIGN =] [PARAM_START (] …
-n, --nodes 不对 CoffeeScript 进行编译, 仅仅 lex 和解析, 打印 parse tree:

Expressions
  Assign
    Value "square"
    Code "x"
      Op *
        Value "x"
        Value "x"
--nodejs node 命令有一些实用的参数, 比如
--debug--debug-brk--max-stack-size, 和 --expose-gc. 用这个参数直接把参数转发到 Node.js. 重复使用 --nodejs 来传递多个参数.

我习惯 这么用:coffee -c -w -o ./js hello.coffee 这样就可以就可以一般编写一边编译,并把编译后的js文件放到指定的文件夹中。

写一个coffee文件:

#打印出Hello World
Console.log "Hello World"

编译命令:

coffee -c hello.coffee

会在同级目录下生成一个同名的js文件。

可以直接使用node命令执行js文件 或者在html中引入让浏览器来执行 ,这里用node直接执行:

node hello.js

Hello World!完成 我们看看coff帮我们编译成了什么样子的js。

// Generated by CoffeeScript 1.7.1
(function() {
console.log("Hello World!");
}).call(this);

CoffeeScript 将js包裹在了一个匿名函数当中,并用call(this)调用,这样使得js代码隔离,不会和外部混淆。

 2.2 作用域

在js中定义变量需要加上var,但是在CoffeeScript中你不需要这样做,直接

age=22
name="silenceper"
say=(arg)->
 console.log "my name is "+arg
say name

对应的js如下:

// Generated by CoffeeScript 1.7.1
(function() {
 var age, name, say;

 age = 22;

 name = "silenceper";

 say = function(arg) {
 var str;
 str = "my name is " + arg;
 return console.log(str);
 };

 say(name);

}).call(this);

可以看到所有的全局变量都会被定义在最顶层,函数内部的局部变量也被加上var定义,防止和局部变量混淆。这一点非常有用,之前就遇到过这样的问题,因为定义了一个变量,刚好这个变量就是dom的id,而我又没有加上var声明,导致ie认为这是一个dom对象,而出现一些莫名奇妙的错误,当然还有很多,相信写js的人也遇到过这样的问题。

2.3 函数

我已经在上面使用了函数,它是通过->的形式来定义一个函数,有参数的话就在前面的括号中写参数,然后通过空格 缩进来表示函数体。

2.4  if/else/unless

其实跟js差不多  只不过使用起来更加方便了,它不需要你加括号、分号来区分,这里也是使用空格、缩进来处理。

day="Thursday"
if day is "Saturday" or "Sunday"
    go "rest"
else
    go "work"

coffeeScript跟js中判断的对比

初识 CoffeeScript

还有存在性判断:就是在变量的后边加上一个?

solipsism = true if mind? and not world?

speed = 0
speed ?= 15

footprints = yeti ? "bear"

2.5 循环

使用for/in 完成数组的循环,使用for/of 完成对象的循环

for/in示例:

eat food for food in ['toast', 'cheese', 'wine']

对于的js

var _ref,food,_i;
_ref = ['toast', 'cheese', 'wine'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  food = _ref[_i];
  eat(food);
}

for/of 示例:

yearsOld = max: 10, ida: 9, tim: 11

ages = for child, age of yearsOld
  "#{child} is #{age}"

注意:其中的#{}就是变量的替换

2.6  switch/when/else

使用官方的示例:

 

switch day
  when "Mon" then go work
  when "Tue" then go relax
  when "Thu" then go iceFishing
  when "Fri", "Sat"
    if day is bingoDay
      go bingo
      go dancing
  when "Sun" then go church
  else go work

对应的js:

switch (day) {
  case "Mon":
    go(work);
    break;
  case "Tue":
    go(relax);
    break;
  case "Thu":
    go(iceFishing);
    break;
  case "Fri":
  case "Sat":
    if (day === bingoDay) {
      go(bingo);
      go(dancing);
    }
    break;
  case "Sun":
    go(church);
    break;
  default:
    go(work);
}

2.7 类/继承

直接参考官方的示例:

class Animal
  constructor: (@name) ->

  move: (meters) ->
    alert @name + " moved #{meters}m."

class Snake extends Animal
  move: ->
    alert "Slithering..."
    super 5

class Horse extends Animal
  move: ->
    alert "Galloping..."
    super 45

sam = new Snake "Sammy the Python"
tom = new Horse "Tommy the Palomino"

sam.move()
tom.move()

对应的js:

var Animal, Horse, Snake, sam, tom,
  __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() {
  function Animal(name) {
    this.name = name;
  }

  Animal.prototype.move = function(meters) {
    return alert(this.name + (" moved " + meters + "m."));
  };

  return Animal;

})();

Snake = (function(_super) {
  __extends(Snake, _super);

  function Snake() {
    return Snake.__super__.constructor.apply(this, arguments);
  }

  Snake.prototype.move = function() {
    alert("Slithering...");
    return Snake.__super__.move.call(this, 5);
  };

  return Snake;

})(Animal);

Horse = (function(_super) {
  __extends(Horse, _super);

  function Horse() {
    return Horse.__super__.constructor.apply(this, arguments);
  }

  Horse.prototype.move = function() {
    alert("Galloping...");
    return Horse.__super__.move.call(this, 45);
  };

  return Horse;

})(Animal);

sam = new Snake("Sammy the Python");

tom = new Horse("Tommy the Palomino");

sam.move();

tom.move();

其实在javascript当中并没有class,extends 这样的用法,只不过为了让使用起来方便,CoffeeScript允许你这样简单的使用。

通过观察编译后的js发现,它是通过一个__extends方法来实现继承这一用法的,其实也是通过更改prototype来实现。

其中的@name 表示的就是this.name

CoffeeScript为了方便使用prototype,可以使用双冒号来替代prototype。

说说注释:

单行注释:使用一个#,这种注释方式不会被编译进js当中

#这是单行注释

多行注释:使用三个#开始,三个#结束。这种注释方式会被编译为/**/的形式

###
这是多行注释
###

其实CoffeeScript当中还有很多奇妙便捷的功能,你可以在CoffeeScript首页的例子中找到。

 

在github中可以找到很多CoffeeScript写的js项目,可以多看看!

另外还有一个js转CoffeeScript的工具:https://github.com/js2coffee/js2coffee


原文地址:http://silenceper.com/archives/1108.html


发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>