2

前言

  • 本文适合没接触过CoffeeScript的人。
  • 如果你想了解下CoffeeScript,可以看这篇笔记。
  • 如果你想学习CoffeeScript,或者找CoffeeScript入门资料,请直接跳到最后看 books 部分。

安装coffee-script

sudo npm install -g coffee-script

编辑器

没找到好用的IDE。

vim可以安装vim-coffee-script

使用Vundle安装,添加以下这行到vimrc。(需要你以前配置好了Vundle。)

Bundle 'kchmck/vim-coffee-script'

启动vim然后运行 :BundleInstall

编译

coffee -cwmo js coffee

会监视改动,同时会生成 source map,记录CoffeeScript和JavaScript的对应关系。

或者使用Harp.js之类的服务器,可以直接放.coffee

rack-coffee和CoffeeCup分别为知名的Ruby和Python框架提供 CoffeeScript中间件,让编译透明化。

Node.js中也可以使用coffee命令直接运行.coffee文件。

浏览器中也可以加载CoffeeScript编译器后直接写CoffeeScript:

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

当然这会损失一些性能。

可以使用js2coffee将JavaScript转为CoffeeScript。

调试

通过打印来调试,例如:

window.debugMode = document.location.hash.match(/debug/) and console?
console.log 'debug mode output' if debugMode

这样只有当地址栏包含#debug,且console开启时才会输出调试信息。

选择Chrome Developer Tools调试的话,记得在设置中开启source map支持。

选择Firefox的话,记得选择23或更新的版本。

基本语法

  • 基于缩进的语法。
  • 数组和哈希表,每项另起一行的话,可以省略逗号。
  • 单引号下\n\t会被解析。单引号和双引号性能差别不大,而且CoffeeScript一般编译后使用,所以运行时单引号并没有性能优势,考虑到以后可能会使用插值字符串,所以尽可能使用双引号是个好主意。
  • ###多行注释,"""'''多行字符串、///多行正则。
  • 字符串插值 #{expression}
  • ==is都会被编译为 JavaScript 中的 ===,避免JavaScript中==那样宽松的、强制类型转化的等于检查造成的问题。CoffeeScript社区有讨论过将==!=移除,强制使用isisnt,以免JavaScript用家混淆。Anyway,尽量使用isisnt是个好主意。
  • Hash table中如果键值不奇怪的话,可以省略引号,相应地如果要用变量作键值,只能写成table[key] = value了。
  • loopwhile true的简写形式,但是只能用于前缀。
  • 参数列...可以用来分割数组,用于函数定义时可以吸收所有多余的参数。
  • a?.b吸收操作符
  • 闭区间 .. 排外区间 ...
  • Python里的x, y = y, x,CoffeeScript下写作[x, y] = [y, x]
  • for语句后面用of遍历哈希表,用in遍历数组,后面可以跟when。和python一样,for循环不生成闭包。in后可跟by,指定步进。
  • 同样,列表解析也不生成闭包,和Python 2一样,和Python 3不同。
  • whileuntil后置的情况下如果起始条件不满足的话代码一次都不会被执行。
  • 条件表达式: condition ? result : else-result
  • ifunlessisisnt,使用起来很方便,很多时候都不需要写not。如果你真打算用not,要留神运算符优先级。a isnt 'a'a is not 'a'是不一样的,后者中先运算not 'a',值为false,整个语句等价于a is false。还有,三元操作符不支持,a? b : c中,b : c会被解析为键值对。
  • 注意,数组即使元素相同也不相等,判断数组是否内容相同需使用arrayEqual = (a, b) -> a.length is b.length and a.every (elem, i) -> elem is b[i]。函数、对象同理。
  • yesontrue的别名,noofffalse的别名。
  • 仅仅在nullundefined时返回false,而if在空字符串和数字0的情况下也返回false
  • 使用模块:User = require("models/user")
  • 如果希望能被其他模块访问:module.exports.f = (x) -> x
  • 除了returncontinuebreak外,一切皆为值。

注意,NaN是一个奇葩,typeof NaN返回number,但是NaN is NaN返回false。IEEE754定义的,算一个tradeoff的设计。把这个放进语言算是JavaScript的坑,然后CoffeeScript没填上。

函数

  • do可以形成闭包,和lua一样。(事实上,do类似lisp中的let。)
  • 隐式返回最后一个表达式的值
  • 函数调用省略括号
  • arguments数组访问传递给函数的所有对象(低可读性)

@namethis.name的简写,this表示上下文环境。相应的,有new关键字,applycall方法。

  • 函数调用前若有new关键字,会把函数作为构造函数创建一个新对象,上下位即为该新对象。
  • 使用call或者apply调用函数时,给定的第一个参数为上下文。
  • 函数作为对象的属性obj.func来调用时,该对象为上下文。
  • 若不满足以上条件,则上下文为全局。

由于上下文在调用时绑定,因此可能会出现预料之外的情况。将->改为=>,可以确保this的意义与函数定义所在位置的this一样。

属性参数可以缩短代码,如

setName = (name) -> @name = name

可以简写为

setName = (@name) ->

使用表达式作默认参数,则表达式将在函数被调用的上下文中执行。

函数调用可以写成do f。例如do (x) -> ...((x) -> ...)(x)的简写,这个例子是node.js循环中捕获变量的常用写法。

  • CoffeeScript会自动将整个类声明封装在do ->中,自己手工封装会报错。
  • @var: value表明这个元素属于constructor(class)而不是prototype(instance)。这与@var = valuethis.var: value不同。
  • 构造函数和其他函数不同,在没有显式return的前提下,返回的是构造对象。

try...catch

try
  odd 5.1
catch e
  console.log e

模块

root属性需要以root.attr的形式明确定义。

root = global ? window

确保同时兼容Node和浏览器环境。

一个文件的exports对象会在另一个文件require调用该文件时返回。

Books

  1. The Little Book on CoffeeScript 简明的介绍,四平八稳。
  2. Smooth CoffeeScript Eloquent JavaScript的CoffeeScript fork,适合没学过编程的人。否则会觉得节奏太迟缓了,这种情况下可以跳到最后看Language Reference。
  3. CoffeeScript 介绍CoffeeScript,感觉比The Little Book要好,然而不是免费的。我读的是同事买的寸志翻译的中文版。
  4. CoffeeScript Ristretto 理解 CoffeeScript 原理。强烈推荐!

私人建议:

如果只打算读1本,那推荐4,这本书不读真是太可惜了。

如果没学过编程,推荐先读2,然后再读4。

如果打算快速上手,那么可以读2——如果不打算花钱买,又借不到,读1也可。以后有空再读4。


weakish
24.6k 声望844 粉丝

a vigorously lazy deadbeat with matured immaturity


引用和评论

0 条评论