函数绑定及其他
函数绑定
JavaScript 当中 this 关键字被动态地设定为当前函数挂载所在的对象上. 如果你把函数当作回调, 或者挂载到别的对象, 那么原先的 this 就丢失了. 如果你不了解这个行为, If you're not familiar with this behavior, this Digital Web article 对怪异模式做了很好的回顾.
Fat arrow => 可以同时定义函数, 绑定函数的 this 到当前的值, 正是我们需要的. 这有助于在 Prototype 或者 jQuery 这种基于回调的类库当中使用, 用于创建迭代器函数传递给 each, 或者借助 bind 的事件处理器函数. Fat arrow 定义的函数可以访问到他们创建位置的 this 对象的属性.
CoffeeScript:编译成JS:
- Account = (customer, cart) ->
- @customer = customer
- @cart = cart
- $('.shopping_cart').bind 'click', (event) =>
- @customer.purchase @cart
- var Account;
- Account = function(customer, cart) {
- this.customer = customer;
- this.cart = cart;
- return $('.shopping_cart').bind('click', (function(_this) {
- return function(event) {
- return _this.customer.purchase(_this.cart);
- };
- })(this));
- };
如果上边用的是 this, @customer 会指向一个 DOM 元素的 undefined "customer" 属性, 然后强行调用上面的 purchase() 时会抛出一个异常.
对于类的定义, 实例创建的过程中 fat arrow 定义的方法会自动绑定到类的每个示例上去。
嵌入 JavaScript
这个写法应该不会被用到, 但如果什么时候需要在 CoffeeScript 中穿插 JavaScript 片段的话, 你可以用反引号直接传进去。
CoffeeScript:编译成JS:
- hi = `function() {
- return [document.title, "Hello JavaScript"].join(": ");
- }`
- var hi;
- hi = function() {
- return [document.title, "Hello JavaScript"].join(": ");
- };
Switch/When/Else
JavaScript 里的 Switch 语句有点难看. 你需要在每个 case 写 break 防止自动进入默认的 case. CoffeeScript 会阻止掉意外的 fall-through. 而且 switch 编译的结果会是可以带 return, 可以被用于赋值的表达式. 格式这样写: switch 判断条件, when 然后子句, else 然后默认的 case.
就像 Ruby, CoffeeScript 里边 switch 语句对于每个子句可以带多个值. 任何一个值匹配的情况下, 子句就会执行.
CoffeeScript:编译成JS:
- 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
- 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);
- }
Switch 语句也可以不写控制条件, 当作 if/else 调用链的一个更整洁的可选写法。
CoffeeScript:编译成JS:
- score = 76
- grade = switch
- when score < 60 then 'F'
- when score < 70 then 'D'
- when score < 80 then 'C'
- when score < 90 then 'B'
- else 'A'
- # grade == 'C'
- var grade, score;
- score = 76;
- grade = (function() {
- switch (false) {
- case !(score < 60):
- return 'F';
- case !(score < 70):
- return 'D';
- case !(score < 80):
- return 'C';
- case !(score < 90):
- return 'B';
- default:
- return 'A';
- }
- })();
Try/Catch/Finally
Try/catch 语句基本上 JavaScript 的一样(尽管它们是表达式执行)。
CoffeeScript:编译成JS:
- try
- allHellBreaksLoose()
- catsAndDogsLivingTogether()
- catch error
- print error
- finally
- cleanUp()
- var error;
- try {
- allHellBreaksLoose();
- catsAndDogsLivingTogether();
- } catch (_error) {
- error = _error;
- print(error);
- } finally {
- cleanUp();
- }
链式对比(Chained Comparisons)
CoffeeScript 从 Python 学习了 链式对比 — 这样判断数值是否在某个范围内在写法上更容易.
CoffeeScript:编译成JS:
- cholesterol = 127
- healthy = 200 > cholesterol > 60
- var cholesterol, healthy;
- cholesterol = 127;
- healthy = (200 > cholesterol && cholesterol > 60);
字符串替换, 块级的字符串, 块级的注释
Ruby 风格的字符串替换也在 CoffeeScript 实现了。 双引号包裹的字符串允许数据替换, 用 #{ ... } 语法,而单引号包裹的字符串仅仅是字面量。
CoffeeScript:编译成JS:
- author = "Wittgenstein"
- quote = "A picture is a fact. -- #{ author }"
- sentence = "#{ 22 / 7 } is a decent approximation of π"
- var author, quote, sentence;
- author = "Wittgenstein";
- quote = "A picture is a fact. -- " + author;
- sentence = "" + (22 / 7) + " is a decent approximation of π";
CoffeeScript 支持多行字符串. 行与行会用一个空格拼接, 除非结尾用了反斜杠. 其中缩进会被忽略。
CoffeeScript:编译成JS:
- mobyDick = "Call me Ishmael. Some years ago --
- never mind how long precisely -- having little
- or no money in my purse, and nothing particular
- to interest me on shore, I thought I would sail
- about a little and see the watery part of the
- world..."
- var mobyDick;
- mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world...";
- loadrun: mobyDick
块级的字符串可以用于书写格式化的或者对缩进敏感的文本(或者你只是不想转义单引号双引号)。代码块开始的位置的缩进层级会被保留, 用在后面的代码中, 所以这部分代码依然可以跟整体的代码一起对齐。
CoffeeScript:编译成JS:
- html = """
- cup of coffeescript
- """
- var html;
- html = "\n cup of coffeescript\n";
块级的字符串用双引号, 跟普通的双引号字符串一样, 支持替换。
有时候你想把整块的注释传给生成的 JavaScript。 比如在文件顶部嵌入协议。 块级的注释, 仿照了块级字符串的语法, 将会在生成的代码当中保留。
CoffeeScript:编译成JS:
- ###
- SkinnyMochaHalfCaffScript Compiler v1.0
- Released under the MIT License
- ###
- /*
- SkinnyMochaHalfCaffScript Compiler v1.0
- Released under the MIT License
- */
块级的正则表达式
类似块级的字符串跟注释, CoffeeScript 支持块级的正则 — 扩展了正则表达式, 可以忽略内部的空格, 可以包含注释和替换. 模仿了 Perl 的 /x 修饰符, CoffeeScript 的块级正则以 /// 为界, 让正则表达式获得了很大程度的可读性. 引用一下 CoffeeScript 源码:
CoffeeScript:编译成JS:
- OPERATOR = /// ^ (
- ?: [-=]> # 函数
- | [-+*/%<>&|^!?=]= # 复合赋值 / 比较
- | >>>=? # 补 0 右移
- | ([-+:])\1 # 双写
- | ([&|<>])\2=? # 逻辑 / 移位
- | \?\. # soak 访问
- | \.{2,3} # 范围或者 splat
- ) ///
- var OPERATOR;
- OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/;
Cake和Cake文件
CoffeeScript包含一个类似GNU Make 和 Ruby的 Rake的构建系统,很自然的,它被称作Cake。它用于构建任务和测试CoffeeScript语言本身。任务被包含在一个Cake文件(cakefile)里,并且可以通过在目录运行Cake任务进行调用。要查看所有的任务选项和设置,只需输入cake命令。
任务的定义是CoffeeScript编写的,所以你可以把任意代码放在cakefile里。定义包含如下内容:任务名称、任务的具体描述,以及任务在运行时调用的函数。如果您的任务需要一个命令行选项,您可以用短和长的标志来定义选项,并且它将在选项对象中可用。这里有一个任务例子,使用Node.js API重建CoffeeScript的解析器:
CoffeeScript:编译成JS:
- fs = require 'fs'
- option '-o', '--output [DIR]', 'directory for compiled code'
- task 'build:parser', 'rebuild the Jison parser', (options) ->
- require 'jison'
- code = require('./lib/grammar').parser.generate()
- dir = options.output or 'lib'
- fs.writeFile "#{dir}/parser.js", code
- var fs;
- fs = require('fs');
- option('-o', '--output [DIR]', 'directory for compiled code');
- task('build:parser', 'rebuild the Jison parser', function(options) {
- var code, dir;
- require('jison');
- code = require('./lib/grammar').parser.generate();
- dir = options.output || 'lib';
- return fs.writeFile("" + dir + "/parser.js", code);
- });
如果您需要在调用一个任务前调用另一个,例如,在run函数前前运行build函数,您可以使用invoke函数:invoke 'build'。Cake任务是一个调用CoffeeScript功能命令行的最简短方式,所以不要期待任何花哨的功能。如果你需要调用某些必须的功能,或异步回调,最好把它们放在你的代码本身,而不是Cake任务里。
转载本站内容时,请务必注明来自W3xue,违者必究。