Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time

CoffeeScript 风格指南

这份文档包含了一系列CoffeeScript编程语言的最佳实战。

希望能有更多的人一起做贡献,不断丰富文档。

请知晓,这是一个仍然在编写的项目:一些内容可能不符合社区习惯,这些内容会根据实际情况修改或删除。

灵感

这份文档的灵感来自与许多风格指南,例如:

目录

## 代码布局 ### 制表符还是空格?

建议只使用空格键,每 2个空格 作为一个缩进级别,不要混用制表符和空格键。

### 最大行长

每行最多包含79个字符

### 空行

顶层函数和类声明语句后应空一行。

在类中的函数声明语句后也应当空一行。

在方法或函数内头尾各空一行可以提高代码的可读性。(例如,为了勾勒出代码逻辑部分)

### 尾随空白

任何一行都不应该包含有尾随空白。

### 可选的逗号

在对象属性或者元素定义,以及需要多行定义的数组中,尽量避免使用逗号。

# 正确
foo = [
  'some'
  'string'
  'values'
]
bar:
  label: 'test'
  value: 87

# 错误
foo = [
  'some',
  'string',
  'values'
]
bar:
  label: 'test',
  value: 87
### 编码

建议使用UTF-8进行源文件编码

## 模块引入

当采用模块化系统(例如CommonJs 模块 AMD 等)时,require语句应当独立成行。

require 'lib/setup'
Backbone = require 'backbone'

模块引入语句应当更具如下顺序进行分组:

  1. 标准库 (如果引入了标准库)
  2. 第三方库
  3. 本地库 (如果引入了本地库)
## 声明、表达式中的空格

在下述情况中,避免使用额外的空格

  • 在括号中

       ($ 'body') # 正确
       ( $ 'body' ) # 错误
  • 逗号前

       console.log x, y # 正确
       console.log x , y # 错误

额外建议:

  • 在下列操作符两边加上 一个空格

    • 赋值: =

      • _定义默认参数的时候也是这样

        test: (param = null) -> # 正确
        test: (param=null) -> # 错误
    • 运算操作: +=, -=, etc.

    • 比较操作: ==, <, >, <=, >=, unless, etc.

    • 四则运算: +, -, *, /, etc.

    • (不要用多余一个的空格去包围操作符)

         # 正确
         x = 1
         y = 1
         fooBar = 3
      
         # 错误
         x      = 1
         y      = 1
         fooBar = 3
## 注释

如果修改的代码有相关注释,也应当对注释进行更新,总之,注释应当和代码功能保持一致。

注释的第一个单词应当大写,除非第一个单词必须使用小写字母。

如果注释内容很少,结尾的内容可以省略

### 块级注释

块级注释应当写在所要解释的代码块之前。

每行块级注释都应当用#和一个空格作为开头,并且应当和所要注释的代码保持同样的缩进。

块级注释由仅包含#的那行行进行分段。

  # This is a block comment. Note that if this were a real block
  # comment, we would actually be describing the proceeding code.
  #
  # This is the second paragraph of the same block comment. Note
  # that this paragraph was separated from the previous paragraph
  # by a line containing a single comment character.

  init()
  start()
  stop()
### 行内注释

行内注释应当紧跟所要注释的代码语句之后,如果行内注释内容特别短,可以直接和语句写在一行内(通常在注释前多加一个空格)。

所有的行内注释都应当由一个#号和一个空格作为开头。

应当尽量限制行内注释的数量,因为他们看起来很像一行代码。

不要去描述那些显而易见的代码运行结果。

  # No
  x = x + 1 # Increment x

而应当着重描述代码的运行逻辑。

  # Yes
  x = x + 1 # Compensate for border
## 命名

使用 camelCase (驼峰式)的格式去命名所有的变量、方法和对象属性。

使用 CamelCase 去命名所有的类 (这种风格参照了PascalCase, CamelCaps, 以及 CapWords, 在other alternatives中有描述.)

(CoffeeScript的官方命名方式是camelcase,这是为了尽可能的和javascript协作,详情可以参照这里。)

对于常量,命名需要使用大写字母和下划线。

CONSTANT_LIKE_THIS

对于私有的函数和变量在开头应当用下划线标注。

_privateMethod: ->
## 函数

(这些规则同样适用于类的定义)

当声明的函数中有参数列表,每个参数之间应当也有一个空格进行间隔。

foo = (arg1, arg2) -> # Yes
foo = (arg1, arg2)-> # No

当声明的函数不需要参数,不要插入额外的括号。

bar = -> # Yes
bar = () -> # No

如果需要进行多次链式调用,不要将他们写在一起,每次调用都应当独立成行,并用两个空格进行缩进,用.开头。

[1..3]
  .map((x) -> x * x)
  .concat([10..12])
  .filter((x) -> x < 11)
  .reduce((x, y) -> x + y)

当调用方法时,为了保持代码的可读性,尽可能的省略不必要的括号。记住一点,"可读性"是主观的,下面的例子,是社区认为处理省略括号比较恰当的方式。

baz 12

brush.ellipse x: 10, y: 20 # Braces can also be omitted or included for readability

foo(4).bar(8)

obj.value(10, 20) / obj.value(20, 10)

print inspect value

new Tag(new Value(a, b), new Arg(c))

有时候,你会发现括号被用来进行函数分组(而不是进行参数分组)。例如使用这种风格。

($ '#selektor').addClass 'klass'

(foo 4).bar 8

这和这种风格不一致:

$('#selektor').addClass 'klass'

foo(4).bar 8

当使用链式调用函数时,一些这种风格的实现更倾向于只在第一次调用的时候使用函数分组。

($ '#selektor').addClass('klass').hide() # Initial call only
(($ '#selektor').addClass 'klass').hide() # All calls

这里不推荐使用函数分组,但是,如果某个项目使用函数分组,也请和项目保持一致,使用函数分组的风格

## 字符串

在字符串中插入变量而不要手动拼接字符串:

"this is an #{adjective} string" # 正确
"this is an " + adjective + " string" # 错误

除非需求是插入双引号,尽可能的使用单引号 ('') 而不是双引号 ("") 字符串,.

## 条件

使用 unless 而不是 if 处理期望条件不成立的情况.

但是不要使用 unless...else, 而使用 if...else:

  # 正确
  if true
    ...
  else
    ...

  # 错误
  unless false
    ...
  else
    ...

多行的 if/else 应当独立成行并使用缩进:

  # 正确
  if true
    ...
  else
    ...

  # 错误
  if true then ...
  else ...
## 循环

尽可能的使用comprehensions进行遍历:

  # 正确
  result = (item.name for item in array)

  # 错误
  results = []
  for item in array
    results.push item.name

处理筛选:

result = (item for item in array when item.name is "test")

遍历键值对:

object = one: 1, two: 2
alert("#{key} = #{value}") for key, value of object
## 扩展类

不要修改原生对象

比如不要在Array.prototype上实现Array#forEach方法

## 异常

不要总是忽略异常.

## 注释

注释应该用于解释代码执行的特定功能

将注释写在所要描述的代码片段之前

注释关键字和注释正文之间应当由一个冒号和一个空格分隔

  # FIXME: The client's current state should *not* affect payload processing.
  resetClientState()
  processPayload()

如果注释有很多行,后续内容用两个空格进行缩进。

  # TODO: Ensure that the value returned by this call falls within a certain
  #   range, or throw an exception.
  analyze()

注释类型:

  • TODO: 标注今后会添加的方法和功能
  • FIXME: 标注需要被修复的代码
  • OPTIMIZE: 标注造成性能瓶颈亟须优化的代码
  • HACK: 标注可疑地或是精巧的代码
  • REVIEW: 标注需要对实现需要进行确认的代码

如果需要自定义注释类型,该注释类型应当记录在项目的README文件中。

## 其他

and优于&&.

or优于||.

is优于==.

not优于!.

尽可能使用or=:

temp or= {} # 正确
temp = temp || {} # 错误

使用(::)访问对象的prototype:

Array::slice # 正确
Array.prototype.slice # 错误

@property优于this.property

return @property # 正确
return this.property # 错误

但是要避免单独使用 @:

return this # 正确
return @ # 错误

除非显式return有助于可读性,否则应尽量避免显式return

当函数的参数数量不固定时,使用splats (...) :

console.log args... # 正确

(a, b, c, rest...) -> # 正确