coffeescript使用的方式汇总


Posted in Javascript onAugust 05, 2015

Coffeescript作为Javascript低调的小弟实在是有过人之处,使用它可以增进开发效率,减少代码错误, 关键是能大幅提升开发愉悦感。我越来越觉得只要可能就在自己的项目中把coffee用起来。

然而也许你和我一样,在了解完coffeescript的语法后准备一试身手的时候,却面对如何把它引入项目而犯起愁来。

像老板一样指挥你的代码

CoffeeScript提供了一堆酷毙了的数组迭代方法。最好的事莫过于这不仅仅能工作于数组,还能工作于jQuery对象了。来行诗一般的代码吧:

formValues = (elem.value for elem in $('.input'))

这行代码将会被翻译为如下的Javascript:

var elem, formValues; 
formValues = (function() { 
 var _i, _len, _ref, _results; 
 _ref = $('.input'); 
 _results = []; 
 for (_i = 0, _len = _ref.length; _i < _len; _i++) { 
  elem = _ref[_i]; 
  _results.push(elem.value); 
 } 
 return _results; 
})();

老实说最初这样写代码确实让人提心吊胆的,但是一旦你开始拥抱CoffeeScript的魔法时,你会爱上它的。

飞一般的方法绑定

在jQuery的回调中使用"=>"将会大大减省你手动绑定方法到对象的麻烦。还是来看段代码吧:

object = 
 func: -> $('#div').click => @element.css color: 'red'

下面是编译输出的Javascript:

var object; 
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 
object = { 
 func: function() { 
  return $('#div').click(__bind(function() { 
   return this.element.css({ 
    color: 'red' 
   }); 
  }, this)); 
 } 
};

代码中的@element指向了一个jQuery的对象,该对象是在其他地方指定的——比如object.element = $('#some_div').

任何使用"=>"所指定的回调函数都会自动绑定到原来的对象上,没错,这很酷。

在2011年函数是这样调用的

瞅一眼这个:

$.post( 
 "/posts/update_title" 
 new_title: input.val() 
 id: something 
 -> alert('done') 
 'json' 
)

使用CoffeeScript,多个参数可以写成多行来调用,逗号和大括弧是可选的,这使得一些jQuery中签名比较长的方法比如$.post() 和 $.animate() 等更加易读。这儿还有一个例子:

$('#thing').animate 
 width: '+20px' 
 opacity: '0.5' 
 2000 
 'easeOutQuad'

很美味的Coffee不是吗?要注意第一个参数是一个匿名的对象,你甚至可以省略调用函数的元括弧。

让初始化来的更性感吧

我最初开始使用jQuery时我是这样做页面初始化的:

$(document).ready(function() { 
 some(); 
 init(); 
 calls(); 
})

CoffeeScript和新版的jQuery使得上面的代码进化的如此性感:

$-> 
 some() 
 init() 
 calls()

函数定义语法在CoffeeScript里本身已经非常酷了,能在上面这些场合使用使得其更酷了。你会发现所有需要回调的函数调用在CoffeeScript中都是如此简单。

其实coffeescript这种语言因其可以一对一地翻译为javascript的特性,使用起来其实非常灵活。 将其引入项目的方式也不止一个。这里,我先就node项目引入coffeescript的方式作一个汇总,并对比一下各个方式的优劣性。

直接使用coffee指令运行纯coffeescript项目

一般提起coffeescript,自然而然地会想到他是javascript的小弟,总脱离不了js的阴影。其实你完全可以把它认作是独立的语言。 我们都知道,在node平台上全局安装完coffee-script包后,就可以通过coffee指令进入coffeescript的交互界面, 叫它repl也行。如果你的项目完全是用coffee写的,那就简单了,直接对你的入口脚本使用coffee指令就结了, 比如你的入口脚本名为“app.coffee”,那就执行:

coffee app.coffee

注意,这里的扩展名coffee是不能省略的。

这个方式应该说是使用coffeescript最“官方”的方式。简单,直接!而且,一旦你以一个coffee文件作为项目的入口, 那整个项目就同时兼容coffee和js了。你在项目里可以任意require js或coffee文件及模块, 甚至可以在项目中的js文件中随便require coffee文件。并且在你引用无论是coffee还是js文件的时候都无需扩展名, 只要前面部分名称不冲突就行。

这个方式有个最大的问题就是,如果它作为一个模块,只能被用于coffee项目;如果他作为一个应用, 运行环境必须安装coffee-script。毕竟coffeescript现在还是一个小众语言,它作为模块时丧失了js用户实在可惜。

另一个也许存在的缺点是性能方面的,毕竟node里面只有js引擎,coffee代码需要先编译为js再运行, 这个过程是要消耗一点点时间的,尽管coffee到js的编译速度其实挺快的。不过这应该不是什么大问题, 一般来说,require都是写在文件的顶部,也就是应用在启动的时候就一气儿把该require的文件都require了, require的时候coffee就被编译成了js放到了js引擎中,那么编译消耗的那点时间都集中在了应用启动时, 运行时几乎不会遇到require新的coffee的情况了。node最常见的使用场景是web服务器,这就更没问题了。

在javascript项目中引用coffeescript

npm中的coffee-script既可以全局安装,也可以作为项目的一个模块安装。那coffee-script作为项目的一个模块有啥意义呢? 其实是给项目添加了一个coffeescript的编译器,这个项目就可以在运行时随时编译coffee文件。

你一定希望像第一种方式里那样随便引用coffee文件。没问题,只需要注册一下。假如你的项目入口文件是app.js, 那么只需要在这个文件最前面加上这么一句:

require('coffee-script/register');

然后你就可以在项目中随便require coffee文件了。

这个方式本质上和第一种方式没啥区别,只不过coffee-script没安装在全局,因此你的模块可以独立存在, 作为应用也不需要环境安装好coffee-script了。

缺点嘛,我觉得最大的问题就是容易让代码有些乱,一会儿js,一会儿coffee,当然第一种方式也可能会这样, 不过都用coffee启动了里面应该不会写js了吧……总之我觉得一个项目还是把语言统一起来比较好 (遗憾的是我主要用这种方式,在一个已经用js写出了大体结构的项目里,我就想用coffee肿么办……)

性能问题上跟第一种方式一样,不多说了。

正统的方式——编译

一说编译,就感觉回到了正儿八经的C或Java的时代。的确,作为一个编译型语言,编译后再运行才是正道。 c有gcc,java有javac,cofee有coffee -c。

要编译一个cofee文件很简单,比如要编辑app.coffee这个文件,就在文件的当前目录执行:

coffee -c app.coffee

一个名为app.js的文件就出现在当前目录下了。这个指令也可以应用于目录, 比如你把项目中所有的coffee源文件放到了src目录下,那就执行:

coffee -c src

src目录及其各级子目录下的所有coffee源文件都会编译成js文件,放到和源文件相同的目录中。

不过对于大型项目,把源文件和编译结果文件放到一起可不太好。指定一个输出目录就行了:

coffee -c -o outputs src

这个指令的参数顺序有点奇怪。在coffee的帮助里是这么定义的:

coffee [options] path/to/script.coffee -- [args]

注意,所有的选项(options)都在coffee和文件路径之间。而最后的args是把目标文件作为脚本执行时给传递的参数。 也就是说所有的选项都放在coffee和文件名之间就可以了。 而-c这个选项是单独的,没有自己的参数,它只表示要把指令最后面提供的那个文件给编译了,所以写成这样也行:

coffee -o outputs -c src

假如想再加个选项,让编译结果不被自执行函数体包围,就是:

coffee -o outputs -c -b src

再假如想把所有源文件编译成一个名为out.js的目标文件,就是:

coffee -o outputs -c -j out src

如果每次改点代码都要这么执行指令也挺烦人的。coffee指令有一个选项-w可以监视源文件的变动而自动编译:

coffee -o outputs -c -w src

对于大型项目来说,最好提前确定好编译方式,让所有开发人员只需要一个指令就搞定所有编译的事情,这就需要自动化构建了。

offee提供了一个自动化构建工具,cake,就像c世界的make。 不过就像官网上说的那样,cake是一个很简单的构建系统。实际上cake的功能就是执行一个名为cakefile的脚本, 而cakefile脚本是用coffeescript写的。这个脚本只提供非常有限的内建函数,比如task, 用于声明一个指令及其对应的描述和执行函数。其它的就是在写一个纯粹的node项目, 想完成编译要么使用node的fs模块输出coffee模块编译出来的字符串, 要么用child_process模块执行shell指令。其实cake构建的目标不一定必须是coffee,由于它实际是执行一个node脚本, 处理任何自动化的事情都可以。

另外还有一些更优秀的第三方自动化构建工具也可以完成coffee的自动编译,比如著名的Grunt,以及国内的fekit等。

这种正统的编译方式也许是看起来最可靠的,应该深受老程序员的喜爱。它可以让团队形成固定的开发模式。 另外,编译后的项目就成了纯的js项目,无论是作为应用直接运行还是作为模块被别的项目引用都不需要额外的依赖。 并且在运行时不需要编译,也就完全不存在编译导致的性能问题了。

缺点嘛,就是太麻烦。如果你是要做一个不太大的项目,光搞cakefile或者配置grunt就要费半天时间,不太值得。

通过jQuery,node.js,javascript中使用coffeescript的介绍,小伙伴们是否对coffeescript有了新的认识了呢

Javascript 相关文章推荐
基于jquery的动态创建表格的插件
Apr 05 Javascript
JQuery+JS实现仿百度搜索结果中关键字变色效果
Aug 02 Javascript
Chosen 基于jquery的选择框插件使用方法
May 30 Javascript
js 验证身份证信息有效性
Mar 28 Javascript
JavaScript使用yield模拟多线程的方法
Mar 19 Javascript
JavaScript实现MIPS乘法模拟的方法
Apr 17 Javascript
AngularJS ng-template寄宿方式用法分析
Nov 07 Javascript
vue通过watch对input做字数限定的方法
Jul 13 Javascript
VUE2 前端实现 静态二级省市联动选择select的示例
Feb 09 Javascript
jQuery实现当拉动滚动条到底部加载数据的方法分析
Jan 24 jQuery
微信小程序实现星级评价
Nov 20 Javascript
JavaScript 如何在浏览器中使用摄像头
Dec 02 Javascript
JS基于FileSystemObject创建一个指定路径的TXT文本文件
Aug 05 #Javascript
JavaScript使用FileSystemObject对象写入文本文件内容的方法
Aug 05 #Javascript
js如何实现点击标签文字,文字在文本框出现
Aug 05 #Javascript
JavaScript实现删除,移动和复制文件的方法
Aug 05 #Javascript
解决jQuery uploadify在非IE核心浏览器下无法上传
Aug 05 #Javascript
JS基于cookie实现来宾统计记录访客信息的方法
Aug 04 #Javascript
JavaScript采用递归算法计算阶乘实例
Aug 04 #Javascript
You might like
PHP中实现crontab代码分享
2015/03/26 PHP
PHP设计模式之迭代器模式Iterator实例分析【对象行为型】
2020/04/26 PHP
PHP执行普通shell命令流程解析
2020/08/24 PHP
js下通过prototype扩展实现indexOf的代码
2010/12/08 Javascript
jquery基础教程之deferred对象使用方法
2014/01/22 Javascript
js处理自己不能定义二维数组的方法详解
2014/03/03 Javascript
JavaScript调用ajax获取文本文件内容实现代码
2014/03/28 Javascript
JS+Canvas 实现下雨下雪效果
2016/05/18 Javascript
仿百度换肤功能的简单实例代码
2016/07/11 Javascript
利用jquery实现下拉框的禁用与启用
2016/12/07 Javascript
利用NPM淘宝的node.js镜像加速nvm
2017/03/27 Javascript
mui上拉加载功能实例详解
2017/04/13 Javascript
bootstrap的常用组件和栅格式布局详解
2017/05/02 Javascript
bootstrap confirmation按钮提示组件使用详解
2017/08/22 Javascript
checkbox:click事件触发span元素内容改变的方法
2017/09/11 Javascript
详解可以用在VS Code中的正则表达式小技巧
2019/05/14 Javascript
详解ES6 Promise的生命周期和创建
2019/08/18 Javascript
Vue可自定义tab组件用法实例
2019/10/24 Javascript
vue:el-input输入时限制输入的类型操作
2020/08/05 Javascript
解决vue net :ERR_CONNECTION_REFUSED报错问题
2020/08/13 Javascript
vue form表单post请求结合Servlet实现文件上传功能
2021/01/22 Vue.js
跟老齐学Python之大话题小函数(2)
2014/10/10 Python
python数组复制拷贝的实现方法
2015/06/09 Python
python实现多线程抓取知乎用户
2016/12/12 Python
TensorFlow实现checkpoint文件转换为pb文件
2020/02/10 Python
Python3和PyCharm安装与环境配置【图文教程】
2020/02/14 Python
Python OpenCV实现测量图片物体宽度
2020/05/27 Python
CSS Houdini实现动态波浪纹效果
2019/07/30 HTML / CSS
财务经理岗位职责
2013/11/09 职场文书
社区学雷锋活动策划方案
2014/01/30 职场文书
网络书店创业计划书
2014/02/07 职场文书
工作疏忽、懈怠的检讨书
2014/09/11 职场文书
学校世界艾滋病日宣传活动总结
2015/05/05 职场文书
致运动员的广播稿
2015/08/19 职场文书
2016优秀护士求职自荐信
2016/01/28 职场文书
一篇文章带你深入了解Mysql触发器
2021/08/02 MySQL