本 系列 文章将探讨 CoffeeScript,这是构建于 ">JavaScript 基础之上的一种全新编程语言,它提供了非常干净的语法。CoffeeScript 可编译为高效的 JavaScript。除了在 Web 浏览器中运行 JavaScript 之外,您还可以将它与服务器应用程序的 Node.js 等技术一起使用。在 第 1 部分 中,学习了如何设置 CoffeeScript 编译器,并使用它创建了随时可在浏览器或服务器中运行的代码。
在本文中,我们将通过解决 Project Euler 中的几个编程问题来探讨 CoffeeScript 语言。文中的示例将指导您使用 CoffeeScript 的函数、作用域、解析 (comprehension)、块语句、数组和一些面向对象的方面。
函数、作用域和解析
您要解决的第一个 Project Euler 问题就是第 6 题,这道题要求您计算前几个自然数的平方和,然后获得这些数字的和的平方,随后算出两者的差值。对于这道题,您将使用 CoffeeScript Read-Evaluate-Print-Loop (REPL)。清单 1展示了 REPL 会话的代码和对应输出。
清单 1. REPL 第 6 题
coffee> square = (x) -> x*x[Function]coffee> sum = (nums) -> nums.reduce (a,b) -> a+b[Function]coffee> diff = (nums) -> (square sum nums) - (sum nums.map square)[Function]coffee> diff [1..100]25164150
详解:
在 REPL 中,定义一个函数。(如 第 1 部分 所述,CoffeeScript 延续了 JavaScript 的函数式编程特色,摒弃了 JavaScript 中大多数类似于 C 语言的语法,因为这些语法加大了实现优雅的函数式编程的难度。)
清单 1 中的示例定义了一个名为 square 的函数,并声明它将获取一个参数,返回该参数自身与自身的乘积(即求其平方)。随后,REPL 告诉您已经定义了一个函数。
定义另外一个名为 sum 的函数,该函数也接受一个参数:一个数组。随后 sum 函数对该数组调用 reduce 方法。
reduce 方法并不是在 CoffeeScript 中新增的,而是 JavaScript 自有的一部分(在 JavaScript 1.8 中添加)。reduce 方法类似于 Python 中的 reduce 函数,或者 Haskell 或 Scala 中的 fold 函数。它获取一个函数,从左至右地遍历数组,将该函数应用于此前由 fold 返回的值和数组中的下一个值。CoffeeScript 紧凑的函数语法使得 reduce 更易于使用。在本例中,传递给 reduce 的函数是由 (a,b) -> a + b 指定的。这个函数将获取两个值,将两值相加,随后将数组中的所有元素相加。
创建一个名为 diff 的函数,该函数将获取一个数字数组,并计算两个子表达式,随后将其相减。第一个子表达式将数组传递给 sum 函数,随后获取结果,并将其传递给 square 函数。
CoffeeScript 允许您在很多情况下忽略圆括号,以避免产生混淆。举例来说,square sum nums 等同于 square(sum(nums))。第二个子表达式调用数组的 map 方法,这也是一个 JavaScript 1.8 方法,以另一个函数作为其输入。随后它会将该函数应用于数组的各成员,根据结果创建一个新数组。清单 1 中的示例使用 square 函数作为 map 的输入参数,为您提供一个使用输入数组元素的平方构成的数组。随后,只需将此传递给 sum 函数,即可获得平方和。
将恰当的数字数组传递到 diff 函数之中,使用作用域 [1..100] 来解答第 6 题。
这个作用域等同于全部由从 1 到 100(包括 1 和 100 在内)的数字构成的数组。如果您希望将 1 和 100 排除在外,那么可以使用 [1...100],使用三个圆点,而非两个。将此传递给 diff 函数即可给出第 6 题的解。
让我们回过头来看看 Project Euler 的第一题,这道题要求您算出 1000 以内可以被 3 或 5 整除的所有整数的和。您可能会认为,这是 Project Euler 中最简单的问题。可以使用函数和作用域来轻松解决此问题,就像解答第 6 题一样。不过,在使用 CoffeeScript 的解析特性时,您可以创建如 清单 2 所示的优雅的解决方案。
清单 2. 使用解析解决第 1 题
coffee> (n for n in [1..999] when n % 3 == 0 or n % 5 == 0).reduce (x,y) -> x+y 233168
仅通过一行代码便可解决问题是最好不过,CoffeeScript 简明的语法使之能够通过单行方式解决问题。清单 2 中的解决方案使用解析创建了是 3 或 5 的倍数的所有整数的列表。首先从作用域 [1..999] 开始生成,但仅使用可被 3 或 5 整除的值。随后使用另外一个 reduce 来求取这些值的和。REPL 将计算这一行代码的结果,并输出问题的解。
下一节将处理略微有些复杂的问题,进一步探讨 CoffeeScript。