在CoffeeScript刚推出的时候关注过,那时候编译出来的JavaScript代码调试起来是个问题。经过不断改进,编译出的JavaScript代码可读性已经不再是问题了。
CoffeeScript是一个CoffeeScript语言到JavaScript的Transcompiler。其语法受到Ruby,Python的印象。如果你曾经使用过Ruby、Python。那么上手CoffeeScript是分分钟的事情。
比如
- Parallel Assignment(ES6中的Destructing,
a, b = [1,2]
) - Postfix modifiers(放在表达式后面的
exp if/unless/while
) - Existential operator(
array.include?
) - Array comprehensions等。(
x for x in array
) - Fat Arraow (x = => {})
- String interpolation("#{variable} world")
在使用过程中遇到了一些问题,总结如下:
无用的数组
和Ruby一样,函数总会返回最后一个表达式的结果。
所以下面的代码中的for循环会被以数组形式返回。为此,会生成一个临时变量result来保存循环中的最后一个表达式,即console.log(x)
。而这个结果有时候是无用的。
a = [1,2,3];
dump = ->
for x in a
console.log(x);
被翻译成
var a, dump;
a = [1, 2, 3];
dump = function() {
var i, len, results, x;
results = [];
for (i = 0, len = a.length; i < len; i++) {
x = a[i];
results.push(console.log(x));
}
return results;
};
避免生成‘无用数组’的的方法很简单,在最后加上一个return就可以了:
a = [1,2,3];
dump = ->
for x in a
console.log(x);
return
被翻译成
var a, dump;
a = [1, 2, 3];
dump = function() {
var i, len, x;
for (i = 0, len = a.length; i < len; i++) {
x = a[i];
console.log(x);
}
};
没有函数声明
CoffeeScript中无法使用函数声明,只有函数表达式,并且都是匿名的。
换句说法就是,CoffeeScript不允许函数提升(Hoisting),也不产生Named Function Expression。
函数声明和具名函数表达式在stack trace时有一定的帮助。
Issue#15和Issue#1640都有对这个feature的请求。
CoffeeScript中唯一出现函数声明的地方就是类定义:
class Clazz
fn: () -> alert(1)
被翻译成
var Clazz;
Clazz = (function() {
function Clazz() {}
Clazz.prototype.fn = function() {
return alert(1);
};
return Clazz;
})();
非primitive的类属性
class Animal
behaviors: ["eat","sleep","drink","run"]
cat = new Animal();
dog = new Animal();
cat.behaviors.push("miaow");
console.log cat.behaviors
# => ["eat", "sleep", "drink", "run", "miaow"]
console.log dog.behaviors
# => ["eat", "sleep", "drink", "run", "miaow"]
dog也有了miaow
的行为。这是因为cat
和dog
实例的behaviors
都指向同一个数组实例。解决的方法是在构造函数中设置behaviors
属性的值:
class Animal
constructor: ->
@behaviors = ["eat","sleep","drink","run"]
cat = new Animal();
dog = new Animal();
cat.behaviors.push("miaow");
console.log cat.behaviors
# => ["eat", "sleep", "drink", "run", "miaow"]
console.log dog.behaviors
# => ["eat", "sleep", "drink", "run"]
函数调用的括号
CoffeeScript中的函数调用可以省略括号。但是有时候会导致意想不到的问题:
x = "hello"
console.log x +1
会被翻译成
var x;
x = "hello";
console.log(x(+1));
注意到了么,x +1
中加好后面没有空格。所以x被当做函数调用,而+1
被当做“正数1”了。
在CoffeeScript源码中使用JavaScript代码
有时候会遇到这样的问题:有一部分历史代码是用JavaScript写的,但是翻译成CoffeeScript代价又比较大。此时可以用backtick(`)在CoffeeScript中嵌入JavaScript代码:
f()
`function f() {`
console.log "hello world!"
`}`
被翻译成
f();
function f() {;
console.log("hello world!");
};
这也算是在CoffeeScript中使用函数声明的一个Trick吧。当然不推荐这样做。
慎用Grunt编译CoffeeScript
最初项目是用Grunt进行构建。但在公司笔记本上,机械硬盘实在不给力,每次保存*.coffee
后带来的编译都要花费1到2秒钟,这一点是无法忍受的。
切换到Gulp之后好了许多。配合ssd效果更好。
至于在ssd上使用Grunt是否这么慢没有进行测试。
总结
CoffeeScript只是JavaScript衣柜里的一件衣服。
衣柜里比较有名的还有:
- Google的 Dart
- 微软的TypeScript
- CoffeeScript作者的另一个语言 LiveScript
随着Babel及其插件的不断完善、Reactjs的流行。CoffeeScript的吸引力变得越来越小。除非你实在不想打花括号和圆括号。