`
xjk2131650
  • 浏览: 57126 次
  • 性别: Icon_minigender_1
  • 来自: 河北
社区版块
存档分类
最新评论

利用 CoffeeScript 和 Node 进行函数式 JavaScript 编程

阅读更多

CoffeeScript 是一种相对较新的语言,为开发人员提供了不再有 JavaScript 缺陷的令人期待的方案。利用 CoffeeScript,开发人员即可使用一种轻量级、直观的语言完成编码工作,这种语言就像是 Ruby 和 Python 的混合体。对于兼容浏览器的 Web 应用程序,CoffeeScript 将编译为 JavaScript;对于服务器端应用程序来说,它还能与 Node.js 无缝地协同工作。本文的核心是使用 CoffeeScript 的第三项收益,也就是处理 JavaScript 的函数 方面的功能。CoffeeScript 拥有整洁、现代化的语法,释放了 JavaScript 库中潜藏的函数式编程世界。

主流编程语言中的函数式编程

尽管没有任何一种主流编程语言(例如 Java™ 语言、C++ 和 C#)明确作为函数式编程语言,但这些语言中的附加库和框架实现了各种级别的函数式编程。更重要的是,像 Clojure、F# 和 Erlang 这样的语言日益趋向主流,因为函数式编程所产生的 bug 更少,而且能提高复杂应用程序的生产力。

与 JavaScript 相似,函数式编程同样非常有用,但也是一段时间非常不受欢迎。JavaScript 最初被视为一种玩具式的语言,而函数式编程则因超高的复杂度而闻名。但随着对高度并发式应用程序的需求增加,人们急需找到一种替代方法来取代现有编程风格。事实证明,函数式编程并不存在传闻中的不必要的复杂性,它是一款出色的工具,能够整理某些类型的应用程序中固有的复杂性。

在这篇文章中,我们将探讨如何利用名为 Underscore 的 JavaScript 库在 CoffeeScript 和 Node 中进行函数式脚本编程。将这三项技术结合,就会构成一种强大的技术体系,使您能利用 JavaScript,开发出运用函数式编程的服务器端和基于浏览器的应用程序。

请注意,这篇文章是在我之前的两篇文章 “Java 开发 2.0:面向 Java 开发人员的 JavaScript” 和 “面向 Java 开发人员的 Node.js” 的基础之上编写的。我假设您的开发环境中包含 Node.js,而且您已经熟悉了 Node 中的基本编程。

设置 CoffeeScript 和 Node

如果您的开发环境中已经安装了 Node.js,那么您可以直接使用它的包管理器 (NPM) 来安装 CoffeeScript。以下命令将告知 NPM 在全局安装包:

 $> npm install -g coffee-script 

使用 CoffeeScript 时,您的大部分时间将花费在编写程序、将其保存为 .coffee 文件、然后将结果编译为 JavaScript 方面。CoffeeScript 的语法与 JavaScript 语法极为接近,因此大多数开发人员都能轻松上手;举例来说,清单 1 中的 CoffeeScript 脚本与 JavaScript 极其相似,只是没有 JavaScript 中常见的那种混乱的括号和分号:


清单 1. 典型的 CoffeeScript
				
 $> coffee -bpe "console.log 'hello coffee'"    console.log('hello coffee'); 

coffee 命令是执行某些管理任务的捷径。它能够将 CoffeeScript 文件编译为 JavaScript、运行 CoffeeScript 文件,甚至可以作为一种交互式环境或者 REPL(类似于 Ruby 的 irb)。

下面,我将我的脚本存到一个文件中:

 console.log "hello coffee" 

随后我将这个文件编译(或转换)为 JavaScript:

 $> coffee -c hello.coffee 

结果获得了一个名为 hello.js 的文件。由于所得到的 JavaScript 脚本对于 Node 同样有效,因此我可以直接在我的 Node 环境中运行它:


清单 2. 在 Node 中运行 JavaScript
				
 $> node hello.js  hello coffee! 

此外,我还可以使用 coffee 命令来运行原始的 .coffee 文件,如清单 3 所示:


清单 3. 在 Node 中运行 CoffeeScript
				
 $> coffee hello.coffee  hello coffee! 

注意观察监控器工具 - watchr

开放源码社区制作了大量便捷的文件监控器实用工具,能够完成运行测试、编译代码等任务。这些工具通常是通过命令行工作的,属于极为轻量级的工具。我们将配置监控器工具,用它来监控我们的开发环境中的所有 .coffee 文件,并在保存时将其编译为 .js 文件。

在实现这个目标时,我喜欢使用的实用工具是 watchr,这是一个 Ruby 库。为了使用 watchr,您的开发环境中需要安装 Ruby 和RubyGems。在安装完成之后,即可运行以下命令,将 watchr 安装为全局 Ruby 库(包括相应的实用工具):

 $> gem install watchr 

在 watchr 中,您使用正则表达式定义要监视的文件,以及应该对其执行的操作。以下命令将 watchr 配置为编译在 src 目录中找到的全部 .coffee 文件:

 watch('src\/.*\.coffee') {|match| system "coffee --compile --output js/ src/"} 

请注意,本例中的 coffee 命令会将所得到的 .js 文件置于一个 js 目录内。

我可以在一个终端窗口中触发这项操作,例如:

 $> watchr project.watchr 

现在,只要我对 src 目录中的任何 .coffee 文件作出修改,watchr 都能确保创建一个新的 .js 文件,并将其放置在我的 js 目录中。

CoffeeScript 概览

CoffeeScript 引入了多种极有价值的特性,因此使用起来比 JavaScript 更容易。CoffeeScript 大体上消除了使用花括号、分号和 var关键字、function 关键字的需要。实际上,我最喜爱的 CoffeeScript 特性之一就是它的函数 定义,如清单 4 所示:


清单 4. CoffeeScript 函数非常简单!
				
 capitalize = (word) -> 
  word.charAt(0).toUpperCase() + word.slice 1

console.log capitalize "andy" //prints Andy

这里,我在 CoffeeScript 中声明了一个简单的函数,将某个词的首字母大写。在 CoffeeScript 中,函数定义的语法紧接一个箭头之后。主体部分也是使用空格分隔的,因此 CoffeeScript 没有花括号。另外还要注意这里没有使用圆括号。CoffeeScript 的 word.slice 1 将编译为 JavaScript 的 word.slice(1)。同样,请注意函数的主题部分也是使用空格分隔的:函数定义行下的所有代码均缩排。下方未缩排的 console.log 表示方法的定义已完整。(CoffeeScript 的这两项特性分别借鉴自 Ruby 和 Python。)

您可能希望了解对应的 JavaScript 函数是怎样的,清单 5 就给出了对应的 JavaScript 代码:


清单 5. 即便是 JavaScript 的单行代码也是非常复杂的
				
 
var capitalize = function(word) {
  return word.charAt(0).toUpperCase() + word.slice(1);
};

console.log(capitalize("andy"));

变量

CoffeeScript 能自动在您定义的任何变量之前添加 JavaScript 形式的 var。因此,在 CoffeeScript 中编写代码时,您不需要牢记var。(JavaScript 中的 var 关键字是可选的。如果没有这个关键字,您的变量将成为全局变量,而这种做法在绝大多数情况下都是不合理的做法。)

CoffeeScript 还允许您为参数定义默认值,如清单 6 所示:


清单 6. 默认参数值!
				
 
greeting = (recipient = "world") -> 
  "Hello #{recipient}"

console.log greeting "Andy" //prints Hello Andy
console.log greeting()      //prints Hello world

清单 7 展示了对应的 JavaScript 脚本对这种默认参数值的处理方法:


清单 7. 杂乱的 JavaScript
				
 var greeting;

greeting = function(recipient) {
 if (recipient == null) recipient = "world";
 return "Hello " + recipient;
};

条件

CoffeeScript 可通过引入 andor 和 not 等关键字处理条件,如清单 8 所示:


清单 8. CoffeeScript 条件
				
 capitalize = (word) -> 
	if word? and typeof(word) is 'string'
		word.charAt(0).toUpperCase() + word.slice 1
	else
		word

console.log capitalize "andy"   //prints Andy
console.log capitalize null     //prints null
console.log capitalize 2        //prints 2
console.log capitalize "betty"  //prints Betty

在清单 8 中,我利用了 ? 操作符来测试条件的存在与否。在尝试将一个词的首字母转为大写之前,这段脚本将确保参数 word 不是null,同时保证它确属 string 类型。CoffeeScript 的出色之处在于允许您使用 is 来取代 ==

函数式编程的类定义

JavaScript 并不直接支持类;它是一种面向原型的语言。对于那些仍然沉浸在面向对象编程中的人来说,这可能让人感到迷惑不解 — 我们想要自己的类!为了满足这种要求,CoffeeScript 提供了一种 class 语法,在编译为标准 JavaScript 时,能获得函数内定义的一系列函数。

在清单 9 中,我使用 class 关键字定义了一个名为 Message 的类:


清单 9. CoffeeScript 确实支持类
				
 
class Message
	constructor: (@to, @from, @message) ->
	
	asJSON:  ->
		JSON.stringify({to: @to, from: @from, message: @message})

mess = new Message "Andy", "Joe", "Go to the party!"
console.log mess.asJSON()

在 清单 9 中,我使用 constructor 关键字定义了一个构造函数。随后,我输入了一个名称,后接一个函数,我用这种方式定义了一个方法 (asJSON)。

CoffeeScript 与 Node

CoffeeScript 脚本将编译为 JavaScript 脚本,因此 CoffeeScript 是在 Node 中进行编程的理想选择,在简化 Node 原本已经非常整洁的代码方面也是非常有帮助的。CoffeeScript 极其擅长简化 Node 的多种回调,通过一个简单的代码对比即可看出这一点。在清单 10 中,我使用纯 JavaScript 方法定义了一个简单的 Node Web 应用程序:


清单 10. 使用 JavaScript 编写的一个 Node.js web 应用程序
				
var express = require('express');

var app = express.createServer(express.logger());

app.put('/', function(req, res) {
  res.send(JSON.stringify({ status: "success" }));
});

var port = process.env.PORT || 3000;

app.listen(port, function() {
  console.log("Listening on " + port);
});

在 CoffeeScript 中重新编写相同的 Web 应用程序,消除 Node 回调的复杂语法,如清单 11 所示:


清单 11. CoffeeScript 简化了 Node.js
				
 
express = require 'express'

app = express.createServer express.logger()

app.put '/', (req, res) ->
  res.send JSON.stringify { status: "success" }

port = process.env.PORT or 3000

app.listen port, ->
  console.log "Listening on " + port

在 清单 11 中,我添加了一个 or 操作符,取代了 JavaScript ||。此外,我还发现,使用箭头来表示 app.listen 中的匿名函数比直接键入 function() 更容易。

CoffeeScript 就像日常语言

现在,您很可能已经认识到,CoffeeScript 倾向于使用抽象符号的日常英语表述形式。在 CoffeeScript 中,我们不是键入 !==,而是可以使用更加直观的 isnt;同样,===也变为了 is

如果您对这个文件执行 coffee -c,那么就会看到 CoffeeScript 生成了与 清单 10 所示几乎完全相同的 JavaScript 脚本。CoffeeScript 中 100% 有效的 JavaScript 脚本可以配合任何 JavaScript 库一起使用。

通过 Underscore 实现函数式集合

作为 JavaScript 编程的函数式实用工具,Underscore.js 是一个能够简化 JavaScript 开发的函数库。除了其他功能之外,Underscore 还提供了一组丰富的面向集合的函数,非常适合处理特殊任务。

举例来说,假设您需要找到一个数字集合内的所有奇数,该数字集合包含从 0 到 10(不含 10)的数字。尽管您能解决这个问题,但结合使用 CoffeeScript 和 Underscore 能使您节约大量键入时间,或许还能减少一些 bug。在清单 12 中,我提供了基本算法,而 Underscore 提供了聚合函数,即本例中的 filter


清单 12. Underscore 的 filter 函数
				
 _ = require 'underscore'

numbers = _.range(10)

odds = _(numbers).filter (x) -> 
	x % 2 isnt 0

console.log odds

首先,由于 _(也就是 underscore)是一个有效的变量名,因此我将其设置为引用 Underscore 库。接下来,我将一个匿名函数附加到了测试奇数的 filter 函数。请注意,我使用了 CoffeeScript isnt 关键字,而非 JavaScript 的 !== 关键字。随后我使用 range 函数指定我希望排序数字 0 至 9,此外,我还为我的范围指定了一个步进计数(即按 2 计数),并从任何数字开始。

filter 函数返回一个数组,这是传递给该函数的数组经过过滤之后的版本,在本例中,返回的数组是 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]。因此运行 清单 12 中的代码将得到 [ 1, 3, 5, 7, 9 ]

map 函数是另外一个我最常应用于 JavaScript 中的集合的函数,如清单 13 所示:


清单 13. Underscore 的 map 函数
				
 oneUp = _(numbers).map (x) ->
	x + 1
	
console.log oneUp

在这里,输出结果应该是 [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]。通常,Underscore 会将 numbers 范围内的各值递增 1,因此我不必手动遍历每一个整数。

如果您需要测试一个集合的多个方面,Underscore 能帮助您简化一切!只需创建一个类似于清单 14 所示的函数即可,这个函数用于测试偶数:


清单 14. Underscore 的 even 函数
				
 even = (x) ->
	x % 2 is 0
	
console.log _(numbers).all(even)
console.log _(numbers).any(even)

定义了 even 函数之后,即可轻松将其连接到 Underscore 函数,如 all 和 any。在本例中,all 将我的 even 函数应用到 numbers 范围中的每一个值。随后返回一个布尔值,指示是否所有 值均为偶数 (false)。类似地,如果有任何 值是偶数 (true),则 any 函数将返回布尔值 true。

利用 Underscore 完成更多任务

本文仅能简单介绍 Underscore 的部分概况。Underscore 的其他特点还包括函数绑定、JavaScript 模板编写和深度相等性的测试。(请参见 参考资料 部分。)

如果您不需要对一个值集合应用任何此类函数,而是需要执行其他一些操作,那么又该怎样做?完全没有问题!利用 Underscore 的 each 函数即可。each 函数作为一个易用的迭代器(也就是说,它能处理场景背后的循环逻辑,在每次迭代时传入指定的函数)。如果您使用过 Ruby 或者 Groovy,那么应该对这种函数感到非常熟悉。


清单 15. Underscore 的 each 函数
				
 
_.each numbers, (x) ->
	console.log(x)

在清单 15 中,each 函数获取一个集合(我的 numbers 范围)和一个需要应用于迭代数组中各值的函数。在本例中,我使用 each 将当前迭代的值输出到控制台。对于我来说,需要做的事情就像将数据保存到数据、将结果返回给用户那样简单。

结束语

CoffeeScript 给 JavaScript 编程注入了新鲜感,也简化了 JavaScript 编程,因此任何用户都能够轻松上手,尤其是熟悉 Ruby 或 Python 的用户。在本文中,我展示了 CoffeeScript 如何通过借鉴这些语言,使 JavaScript 风格的代码更易于阅读,同时还能显著加快编写过程。正如我所演示的那样,将 CoffeeScript、Node 与 Underscore 相结合,即可得到超轻量级的有趣开发堆栈 (development stack),该堆栈适用于基本函数式编程场景。经过一段时间的练习,您就可以将本文所学知识作为基础,深入研究依靠动态 Web 和移动交互的更为复杂的业务应用程序。

分享到:
评论

相关推荐

    CoffeeScript - Accelerated JavaScript Development

    4. **强大的功能**:CoffeeScript支持函数式编程特性,如map、filter等,提供了强大的数据处理能力。 #### 三、CoffeeScript的实际应用 - **Web开发**:CoffeeScript可以用于前端Web开发,与HTML、CSS结合使用,...

    Coffeescript中文手册

    CoffeeScript 是一种简洁、优雅的编程语言,它旨在简化JavaScript的编写,提供更易读、易写的代码。通过CoffeeScript编写的代码会被自动编译成JavaScript,因此可以在任何支持JavaScript的环境中运行。以下是对标题...

    Leanpub.JavaScript.and.Node.FUNdamentals.May.2014

    这部分内容专注于Node.js环境下的JavaScript编程。Node.js是一个基于Chrome V8引擎的JavaScript运行时,它让开发者能够在服务器端使用JavaScript。Node.js采用事件驱动、非阻塞I/O模型,非常适合构建高性能、轻量级...

    NODEJS+NPM+COFFEESCRIPT

    这个压缩包可能包含了使用Node.js、NPM和CoffeeScript进行Web开发的相关教程、示例代码或者项目。学习这些内容,开发者可以掌握如何在服务器端利用JavaScript,利用NPM管理依赖,以及使用CoffeeScript编写更简洁、易...

    coffeescript-cookbook:咖啡脚本食谱

    《咖啡脚本食谱》是一本专注于CoffeeScript编程语言的指南,旨在帮助开发者掌握和运用这一简洁、优雅的JavaScript预处理器。CoffeeScript以其简洁的语法和可读性强的特点,深受许多开发者的喜爱,尤其在前端开发领域...

    nodejs小书(中文版)

    7. 函数返回函数与Currying(柯里化):函数式编程的技巧,它们可以提高代码的模块化和重用性。 8. 流程控制:指的是对程序中数据流和控制流的管理,包括条件判断和循环结构等。 9. Node.js的安装与配置:书中详细...

    Javascript

    同时,JavaScript也是学习其他编程语言的良好基础,如TypeScript、CoffeeScript等。总的来说,JavaScript是互联网时代不可或缺的技术之一,对于任何想要从事Web开发的人来说,掌握JavaScript都是必要的。

    coffeescript-boilerplate:CoffeeScript 项目的样板代码

    CoffeeScript 是一种简洁、优雅的编程语言,它编译成 JavaScript,使得编写 JavaScript 更加简单和易读。 ### CoffeeScript 的基础知识 CoffeeScript 是由 Jeremy Ashkenas 创建的,它的语法设计受到了 Ruby 和 ...

    p5js-coffeescript-browserify:p5.j​​s CoffeeScript浏览器修改示例

    p5.js是一个强大的JavaScript库,它简化了在Web浏览器中进行创意编程的过程,而CoffeeScript则是一种简洁、易于阅读的JavaScript预处理器语言。在这个示例中,开发者可以体验到CoffeeScript的优雅语法与p5.js的功能...

    Y分钟学习X种语言

    LiveScript是CoffeeScript的间接后裔,有着函数式编程特征,例如模式匹配函数函数组合。 有兴趣的可以看一下10 LiveScript one liners to impress your friends。 尝试 Elm 语言 Elm是一种函数式兼反应式(reactive)...

    brunch-phaser-coffee:使用Phaser 3和CoffeeScript制作游戏的早午餐骨架

    2. **CoffeeScript**:CoffeeScript的语法简洁且富有表现力,它通过类、闭包和函数表达式等特性让JavaScript代码更易于理解和编写。在"brunch-phaser-coffee"中,CoffeeScript被用于编写游戏的业务逻辑,以减少代码...

    Windows10UWPFramerJS原型开发工具包

    要开始使用这个工具包,你需要有基本的JavaScript编程知识,最好是熟悉FramerJS和UWP开发环境。安装Node.js和Visual Studio(带有UWP开发工作负载)是必要的,因为它们提供了解析和运行FramerJS项目所需的环境。 在...

Global site tag (gtag.js) - Google Analytics