使用CoffeeScrip优美方式编写javascript代码

JavaScript无疑是在web最伟大的发明之一,几乎一切网页动态效果都是基于它丰富的计算能力。而且它的能力在各种新的JavaScript的Engine下也越来越强了,比如Google Chrome用的V8 Engine。

但是由于诞生的太早,有很多语法定义在今天看来有些效率低下了,一些更加先进的语法形式,由于历史原因,没办法加入到现在的JavaScript语言中,可以说一种遗憾。

世界上的很多天才都在为构建更好的JavaScript而努力。已经有了很多尝试,其中最有前途的,无非就是CoffeeScript和TypeScript了。面对CoffeeScript,我有一见如故的感觉;而TypeScript也激发了我极大的兴趣。CoffeeScript和TypeScript一样,都是编译为JavaScript的语言,它们都增强了JavaScript的表达能力。这篇文章是讲CoffeeScript的,TypeScript将放在下一篇再讲。

所谓编译为JavaScript,是指CoffeeScript和TypeScript没有实现自己的运行时,它们都是编译为等价的JavaScript代码,然后放在JavaScript的解释器上运行。

CoffeeScript

简洁性

CoffeeScript给人最大的印象就是其简洁的表达。下面代码是我从CoffeeScript中文摘抄下来的:

# 赋值:
number  = 42
opposite = true
# 条件:
number = -42 if opposite
# 函数:
square = (x) -> x * x
# 数组:
list = [1, 2, 3, 4, 5]
# 对象:
math =
 root:  Math.sqrt
 square: square
 cube:  (x) -> x * square x
# Splats:
race = (winner, runners...) ->
 print winner, runners
# 存在性:
alert "I knew it!" if elvis?
# 数组 推导(comprehensions):
cubes = (math.cube num for num in list)

上面的代码会编译为等价的JavaScript代码:

var cubes, list, math, num, number, opposite, race, square,
 __slice = [].slice;
number = 42;
opposite = true;
if (opposite) {
 number = -42;
}
square = function(x) {
 return x * x;
};
list = [1, 2, 3, 4, 5];
math = {
 root: Math.sqrt,
 square: square,
 cube: function(x) {
  return x * square(x);
 }
};
race = function() {
 var runners, winner;
 winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
 return print(winner, runners);
};
if (typeof elvis !== "undefined" && elvis !== null) {
 alert("I knew it!");
}
cubes = (function() {
 var _i, _len, _results;
 _results = [];
 for (_i = 0, _len = list.length; _i < _len; _i++) {
  num = list[_i];
  _results.push(math.cube(num));
 }
 return _results;
})();
run: cubes

CoffeeScript力求简洁。其简洁性首先表现在对一些仅用于语法控制的符号进行了去除。这其中包括:

取消分号

取消var声明

取消大括号包围内层代码,使用缩进取代

函数调用在没有歧义的情况下可以省略括号

var声明涉及到复杂又很鸡肋的JavaScript变量作用域机制。这部分内容先放着不讲。CoffeeScript通过完全取消var声明机制而使得问题得到简化。总之,在CoffeeScript世界里,变量不用事先声明,直接用就是了。而且这种用法基本没有什么危险。

缩进在CoffeeScript中不仅仅在于美化代码,其代表了代码层次的组织,是有特别的含义的。简单地说就是,不适用大括号包围内层代码,而是内层代码要缩进。不同的缩进代表了不同的代码层次。形式和内容是一致的。

缩进的例子:

#if缩进
if true
 'true'
else
 'false'
#while缩进
while true
 'true'
#函数缩进
(n) ->
 n * n
#对象字面量缩进
kids =
 brother:
  name: "Max"
  age: 11
 sister:
  name: "Ida"
  age: 9 

在不引起歧义的情况下,CoffeeScript的函数调用可以省略括号。例如console.log(object)可以简化为console.log object。所谓引起歧义的一个例子就是无参数的情况下,console.log就不知道是取出函数型属性log还是调用函数log了。

CoffeeScript的函数表达式也做了极致的精简精简。一个单行函数的定义可以这样:

square = (x) -> x * x

而多行函数也是通过缩进来组织的。一个空的函数最为简洁,是这样:->。

函数的这种简洁表达使得传递回调函数非常便利。一个数组的map可能像这样就足够了:

list = [1, 2, 3]
list.map (e) -> e+1

而等效的JavaScript代码就不能这么马虎:

list = [1, 2, 3];
list.map(function(e) { return e + 1; });

增强的表达

CoffeeScript提供了JavaScript所没有的一些强大的表达语法,这也是被称为语法糖的东西。在我印象中,这种增强性是很多的,我举出两个有代表性的例子:

字符串插值法

列表解析

其中字符串插值法是对现有字符串能力的一种扩充和语法上的简化;而列表解析就要涉及到观念上的改变了。前者是一种改良,后者则是一种变革。

字符串插值法

在CoffeeScript的字符串里,可以用#{…}嵌入一个表达式。例如:

"#{ 22 / 7 } is a decent approximation of π"

等价于:

"" + (22 / 7) + " is a decent approximation of π";

插值在这里起到占位的作用,使得动态内容的字符串更容易构建。我想人人都能接受这样的表达。

列表解析

列表解析是CoffeeScript的世界里的重要一员。它改变了循环的思路。CoffeeScript没有提供像JavaScript那样的for循环结构,而是统统转化为列表解析。一个常规的JavaScript for循环,像下面这样:

food_list = ['toast', 'cheese', 'wine'];
for (i = 0, len = food_list.length; i < len; i++) {
 food = food_list[i];
 eat(food);
}

用CoffeeScript实现就是:

food_list = ['toast', 'cheese', 'wine']
eat food for food in food_list #做个小补充,for循环的单条语句的写法

单单是上面的例子不足以显示列表解析的强大(却看到它的简洁了)。在继续这个话题之前,我觉得我有必要补充一下另一个涉及到CoffeeScript理念的东西了:一切皆是表达式。

在CoffeeScript世界里,一切语句都是表达式语句,都会返回一个值。函数调用默认会返回最后一条语句的值。if条件结构也会返回值,其返回的是执行的最后一条语句的值。循环结构有些不同,其会将每次循环的结果都保存在一个数组里,作为此循环结构的值。例如下面代码的list结果就是[5, 4, 3, 2, 1]。

num = 6
list = while num -= 1
 num

回到列表解析的主题。与while一样,for结构也是一种循环的表达,其结果也是一个数组。回到先前的例子,下面的小代码的list结果就是['t', 'c', 'w']。

food_list = ['toast', 'cheese', 'wine']
list = (food[0] for food in food_list)

我们已经看到for循环的each形式

eat food for food in food_list

以及它的map形式

(food[0] for food in food_list)

下面给出它的filter形式

(food for food in food_list when food is 'wine')

列表解析的特色的地方在于它改变了我们组织循环的方式和解析数组的模式。这是一种声明式的编程方法,告诉程序你想要什么而不去关心构建的过程。

类的支持

类是CoffeeScript对JavaScript的一个很重要的补充。JavaScript的原型功能很强大,写法上又恨别扭。正确地设置原型链以实现继承关系也是个很大的挑战。CoffeeScript从语法上直接支持类的定义,自然且隐藏细节。

class Animal
 constructor: (@name) ->
 move: (meters) ->
  alert @name + " moved #{meters}m."
class Snake extends Animal
 move: ->
  alert "Slithering..."
  super 5
class Horse extends Animal
 move: ->
  alert "Galloping..."
  super 45
sam = new Snake "Sammy the Python"
tom = new Horse "Tommy the Palomino"
sam.move()
tom.move()

从实现上来说,CoffeeScript的类与JavaScript的构造函数和原型链那一套并无二致。所以,理解原型机制也是理解CoffeeScript类的基础。

关于JavaScript的糟粕

CoffeeScript的另一个目标是从语法层面上直接消除JavaScript的被人诟病的一些糟粕部分。前面已经说过关于分号的部分。关于var声明的部分。分号的机制暂且不去例会,总之CoffeeScript不用再去写分号了。

在JavaScript当中,最为人诟病的糟粕部分有两处,因为它们使用的情况最多而且容易出错。

全局变量

相等比较

全局变量

JavaScript的作用域规则很复杂,涉及到var声明机制和变量提升。在JavaScript里,构造一个全局变量是很容易的,有三种方式:

在全局的环境里用var声明

var name = 'name';

在函数内用省略var的方式定义

function foo() {
  name = 'name';
}

绑定到window的属性

window.name = 'name';

其中第1种和第2种方式是最常见的错误用法。首先不推荐直接在全局环境中编码,而是应该用一个匿名函数包裹起来,将程序的作用域限制在这个匿名函数中。第二种用法完完全全就是忘记了var声明。而我在实际的JavaScript编码中,忘记var声明是常有的事(就像经常忘记行末补上分号一样)。

而在CoffeeScript里面就完全没有这种担心了。首先,编译后的JavaScript代码不会暴露在全局环境里,所有的代码都是自动包裹在一个匿名函数(function(){ ... })();内。然后,所有的变量都会自动加上var声明。这就使得不小心污染全局的情况很难发生,除非使用赋值到window上。

相等比较

我们都知道JavaScript有两种比较运算符:==和===。我们也知道==在使用的过程中会很坑,所以平时都宁愿多打一个字符而使用===。CoffeeScript的只有一种比较运算符==,而它会编译成JavaScript的===,从而很好地避过了这道坑。

是否该使用CoffeeScript

CoffeeScript简化和增强了JavaScript的表达能力,尽可能地从语法层面上就能避免JavaScript的一些坑。用它写代码,会让人有更清晰舒适的感觉,而且不容易犯错。CoffeeScript的初衷就是提供更好的JavaScript。

然而,CoffeeScript与JavaScript是不兼容的。它既不是JavaScript的子集,也不是超集,而是与JavaScript有着显然不同思路的一种语言。用CoffeeScript编程就必然要转换观念,尽管这种观念更好更自然,但却是有些固步自封的人望而却步的主要原因了。

CoffeeScript并不是适合每一个人的。有些人对于用缩进组织代码层次完全不能接受,也不能接受用箭头函数表达法。对于他们来说,去掉function关键字和大括号的组织怎么看都怎么地不顺眼。

列表解析很强大,却也显得过于简洁了。对于习惯了构造冗杂JavaScript程序的人们来说,并不习惯这种表达方式。

总之,是不可强求别人去学习使用CoffeeScript。JavaScript已经足够强大,只要足够小心,完全可以使用JavaScript很好地完成工作。对于那些想要尝试CoffeeScript,我们也要给予鼓励的态度,他们是求新求变的勇士。CoffeeScript真的值得一试,而且它真的很小巧,完全掌握它不是件困难的事。

对于在团队推行CoffeeScript,我本人更是持有保守的看法。如果团队从一开始就使用CoffeeScript还好。如果是要从CoffeeScript转为JavaScript,就要谨慎行之。一种可行的方式是先尝试在一个小项目中使用CoffeeScrip,看看效果如何。

对于个人来说,就没有什么限制了。如果真的喜欢,就去尝试吧。你可以使用CoffeeScript写脚本,构建自己的网站,做一些小玩意。

以上内容是小编给大家介绍的使用CoffeeScrip优美方式编写javascript代码,希望大家喜欢。

(0)

相关推荐

  • 当jQuery遭遇CoffeeScript的时候 使用分享

    当我多年前初次接触jQuery时我感觉我来到了程序员的天堂.它极大简化了DOM操作.函数式编程变得如此容易,尽管更多适合RIA开发的框架近年来在浮现,但是我仍旧无法想象一个没有jQuery的程序人生是多么的罪恶,相信你也有同感~ 而来到CoffeeScript的世界,同样的美妙故事再次上演.在写了几行代码后我相信你将不会再想念原生的Javascript了.CoffeeScript包含了许多新特性,当将它与jQuery结合时,你会发现一片新天地. 本文的目的就在于展示CoffeeScript和jQ

  • 使用coffeescript编写node.js项目的方法汇总

    Node.js 基于JavaScript编写应用,JavaScript是我的主要开发语言.CoffeeScript是编译为JavaScript的编程语言.其实CoffeeScript语言因其可以一对一的翻译为JavaScript的特性,使用起来也非常灵活.将其引入项目的方式也有很多种,在此,我将使用coffeescript编写node.js项目的方法做一个汇总. 直接使用coffee指令运行纯coffeescript项目 一般提起coffeescript,自然而然地会想到他是javascript

  • coffeescript使用的方式汇总

    Coffeescript作为Javascript低调的小弟实在是有过人之处,使用它可以增进开发效率,减少代码错误, 关键是能大幅提升开发愉悦感.我越来越觉得只要可能就在自己的项目中把coffee用起来. 然而也许你和我一样,在了解完coffeescript的语法后准备一试身手的时候,却面对如何把它引入项目而犯起愁来. 像老板一样指挥你的代码 CoffeeScript提供了一堆酷毙了的数组迭代方法.最好的事莫过于这不仅仅能工作于数组,还能工作于jQuery对象了.来行诗一般的代码吧: formVa

  • 使用CoffeeScrip优美方式编写javascript代码

    JavaScript无疑是在web最伟大的发明之一,几乎一切网页动态效果都是基于它丰富的计算能力.而且它的能力在各种新的JavaScript的Engine下也越来越强了,比如Google Chrome用的V8 Engine. 但是由于诞生的太早,有很多语法定义在今天看来有些效率低下了,一些更加先进的语法形式,由于历史原因,没办法加入到现在的JavaScript语言中,可以说一种遗憾. 世界上的很多天才都在为构建更好的JavaScript而努力.已经有了很多尝试,其中最有前途的,无非就是Coffe

  • 【经验总结】编写JavaScript代码时应遵循的14条规律

    本文讲述了编写JavaScript代码时应遵循的14条规律.分享给大家供大家参考,具体如下: 1. 总是使用 'var' 在javascript中,变量不是全局范围的就是函数范围的,使用"var"关键词将是保持变量简洁明了的关键.当声明一个或者是全局或者是函数级(function-level)的变量,需总是前置"var"关键词,下面的例子将强调不这样做潜在的问题. 不使用 Var 造成的问题 var i=0; // This is good - creates a

  • JavaScript代码优雅,简洁的编写技巧总结

    1. 强类型检查 用===代替 == // 如果处理不当,它会极大地影响程序逻辑.这就像,你想向左走,但由于某种原因,你向右走 0 == false // true 0 === false // false 2 == "2" // true 2 === "2" // false // 例子 const value = "500"; if (value === 500) { console.log(value); // 条件不成立,不会进入 } i

  • 编写高性能Javascript代码的N条建议

    多年来,Javascript一直在web应用开发中占据重要的地位,但是很多开发者往往忽视一些性能方面的知识,特别是随着计算机硬件的不断升级,开发者越发觉得Javascript性能优化的好不好对网页的执行效率影响不明显.但在某些情况下,不优化的Javascript代码必然会影响用户的体验.因此,即使在当前硬件性能已经大大提升的时代,在编写Javascript代码时,若能遵循Javascript规范和注意一些性能方面的知识,对于提升代码的可维护性和优化性能将大有好处. 下面给出编写高性能的Javas

  • iOS中使用JSPatch框架使Objective-C与JavaScript代码交互

    JSPatch是GitHub上一个开源的框架,其可以通过Objective-C的run-time机制动态的使用JavaScript调用与替换项目中的Objective-C属性与方法.其框架小巧,代码简洁,并且通过系统的JavaScriptCore框架与Objective-C进行交互,这使其在安全性和审核风险上都有很强的优势.Git源码地址:https://github.com/bang590/JSPatch. 一.从一个官方的小demo看起 通过cocoapods将JSPath集成进一个Xcod

  • 深入理解JavaScript系列(1) 编写高质量JavaScript代码的基本要点

    具体一点就是编写高质量JavaScript的一些要素,例如避免全局变量,使用单变量声明,在循环中预缓存length(长度),遵循代码阅读,以及更多. 此摘要也包括一些与代码不太相关的习惯,但对整体代码的创建息息相关,包括撰写API文档.执行同行评审以及运行JSLint.这些习惯和最佳做法可以帮助你写出更好的,更易于理解和维护的代码,这些代码在几个月或是几年之后再回过头看看也是会觉得很自豪的. 书写可维护的代码(Writing Maintainable Code ) 软件bug的修复是昂贵的,并且

  • 编写高质量JavaScript代码的基本要点

    才华横溢的Stoyan Stefanov,在他写的由O'Reilly初版的新书<JavaScript Patterns>(JavaScript模式)中,我想要是为我们的读者贡献其摘要,那会是件很美妙的事情.具体一点就是编写高质量JavaScript的一些要素,例如避免全局变量,使用单变量声明,在循环中预缓存length(长度),遵循代码阅读,以及更多. 此摘要也包括一些与代码不太相关的习惯,但对整体代码的创建息息相关,包括撰写API文档.执行同行评审以及运行JSLint.这些习惯和最佳做法可以

  • 如何利用Promises编写更优雅的JavaScript代码

    你可能已经无意中听说过 Promises,很多人都在讨论它,使用它,但你不知道为什么它们如此特别.难道你不能使用回调么?有什么了特别的?在本文中,我们一起来看看 Promises 是什么以及如何使用它们写出更优雅的 JavaScript 代码. Promises 易于阅读 比如说我们想从 HipsterJesus 的API中抓取一些数据并将这些数据添加到我们的页面中.这些 API 的响应数据形式如下: { "text": "<p>Lorem ipsum...<

  • JavaScript深入V8引擎以及编写优化代码的5个技巧

    概述 JavaScript引擎是执行 JavaScript 代码的程序或解释器.JavaScript引擎可以实现为标准解释器,或者以某种形式将JavaScript编译为字节码的即时编译器. 以为实现JavaScript引擎的流行项目的列表: V8 - 开源,由 Google 开发,用 C ++ 编写 Rhino - 由 Mozilla 基金会管理,开源,完全用 Java 开发 SpiderMonkey - 是第一个支持 Netscape Navigator 的 JavaScript 引擎,目前正

  • 2019 年编写现代 JavaScript 代码的5个小技巧(小结)

    内容基本是今年从其他大神的文章学习到的东西.分享给大家: 1 Array.includes 与条件判断 一般我们判断或用 || // condition function test(fruit) { if (fruit == "apple" || fruit == "strawberry") { console.log("red"); } } 如果我们有更多水果 function test(fruit) { const redFruits = [

随机推荐