CoffeeScript 代碼風(fēng)格指南

CoffeeScript Style Guide

This guide presents a collection of best-practices and coding conventions for the CoffeeScript programming language.

This guide is intended to be community-driven, and contributions are highly encouraged.

Please note that this is a work-in-progress: there is much more that can be specified, and some of the guidelines that have been specified may not be deemed to be idiomatic by the community (in which case, these offending guidelines will be modified or removed, as appropriate).

Inspiration

The details in this guide have been very heavily inspired by several existing style guides and other resources. In particular:

Table of Contents

<a name="code_layout"/>

Code layout

<a name="tabs_or_spaces"/>

Tabs or Spaces?

Use spaces only, with 2 spaces per indentation level. Never mix tabs and spaces.

<a name="maximum_line_length"/>

Maximum Line Length

Limit all lines to a maximum of 79 characters.

<a name="blank_lines"/>

Blank Lines

Separate top-level function and class definitions with a single blank line.

Separate method definitions inside of a class with a single blank line.

Use a single blank line within the bodies of methods or functions in cases where this improves readability (e.g., for the purpose of delineating logical sections).

<a name="trailing_whitespace"/>

Trailing Whitespace

Do not include trailing whitespace on any lines.

<a name="optional_commas"/>

Optional Commas

Avoid the use of commas before newlines when properties or elements of an Object or Array are listed on separate lines.

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

# No
foo = [
  'some',
  'string',
  'values'
]
bar:
  label: 'test',
  value: 87

<a name="encoding"/>

Encoding

UTF-8 is the preferred source file encoding.

<a name="module_imports"/>

Module Imports

If using a module system (CommonJS Modules, AMD, etc.), require statements should be placed on separate lines.

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

These statements should be grouped in the following order:

  1. Standard library imports (if a standard library exists)
  2. Third party library imports
  3. Local imports (imports specific to this application or library)

<a name="whitespace"/>

Whitespace in Expressions and Statements

Avoid extraneous whitespace in the following situations:

  • Immediately inside parentheses, brackets or braces

       ($ 'body') # Yes
       ( $ 'body' ) # No
    
  • Immediately before a comma

       console.log x, y # Yes
       console.log x , y # No
    

Additional recommendations:

  • Always surround these binary operators with a single space on either side

    • assignment: =

      • Note that this also applies when indicating default parameter value(s) in a function declaration

        test: (param = null) -> # Yes
        test: (param=null) -> # No
        
    • augmented assignment: +=, -=, etc.

    • comparisons: ==, <, >, <=, >=, unless, etc.

    • arithmetic operators: +, -, *, /, etc.

    • (Do not use more than one space around these operators)

         # Yes
         x = 1
         y = 1
         fooBar = 3
      
         # No
         x      = 1
         y      = 1
         fooBar = 3
      

<a name="comments"/>

Comments

If modifying code that is described by an existing comment, update the comment such that it accurately reflects the new code. (Ideally, improve the code to obviate the need for the comment, and delete the comment entirely.)

The first word of the comment should be capitalized, unless the first word is an identifier that begins with a lower-case letter.

If a comment is short, the period at the end can be omitted.

<a name="block_comments"/>

Block Comments

Block comments apply to the block of code that follows them.

Each line of a block comment starts with a # and a single space, and should be indented at the same level of the code that it describes.

Paragraphs inside of block comments are separated by a line containing a single #.

  # 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()

<a name="inline_comments"/>

Inline Comments

Inline comments are placed on the line immediately above the statement that they are describing. If the inline comment is sufficiently short, it can be placed on the same line as the statement (separated by a single space from the end of the statement).

All inline comments should start with a # and a single space.

The use of inline comments should be limited, because their existence is typically a sign of a code smell.

Do not use inline comments when they state the obvious:

  # No
  x = x + 1 # Increment x

However, inline comments can be useful in certain scenarios:

  # Yes
  x = x + 1 # Compensate for border

<a name="naming_conventions"/>

Naming Conventions

Use camelCase (with a leading lowercase character) to name all variables, methods, and object properties.

Use CamelCase (with a leading uppercase character) to name all classes. (This style is also commonly referred to as PascalCase, CamelCaps, or CapWords, among other alternatives.)

(The official CoffeeScript convention is camelcase, because this simplifies interoperability with JavaScript. For more on this decision, see here.)

For constants, use all uppercase with underscores:

CONSTANT_LIKE_THIS

Methods and variables that are intended to be "private" should begin with a leading underscore:

_privateMethod: ->

<a name="functions"/>

Functions

(These guidelines also apply to the methods of a class.)

When declaring a function that takes arguments, always use a single space after the closing parenthesis of the arguments list:

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

Do not use parentheses when declaring functions that take no arguments:

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

In cases where method calls are being chained and the code does not fit on a single line, each call should be placed on a separate line and indented by one level (i.e., two spaces), with a leading ..

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

When calling functions, choose to omit or include parentheses in such a way that optimizes for readability. Keeping in mind that "readability" can be subjective, the following examples demonstrate cases where parentheses have been omitted or included in a manner that the community deems to be optimal:

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))

You will sometimes see parentheses used to group functions (instead of being used to group function parameters). Examples of using this style (hereafter referred to as the "function grouping style"):

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

(foo 4).bar 8

This is in contrast to:

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

foo(4).bar 8

In cases where method calls are being chained, some adopters of this style prefer to use function grouping for the initial call only:

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

The function grouping style is not recommended. However, if the function grouping style is adopted for a particular project, be consistent with its usage.

<a name="strings"/>

Strings

Use string interpolation instead of string concatenation:

"this is an #{adjective} string" # Yes
"this is an " + adjective + " string" # No

Prefer single quoted strings ('') instead of double quoted ("") strings, unless features like string interpolation are being used for the given string.

<a name="conditionals"/>

Conditionals

Favor unless over if for negative conditions.

Instead of using unless...else, use if...else:

  # Yes
  if true
    ...
  else
    ...

  # No
  unless false
    ...
  else
    ...

Multi-line if/else clauses should use indentation:

  # Yes
  if true
    ...
  else
    ...

  # No
  if true then ...
  else ...

<a name="looping_and_comprehensions"/>

Looping and Comprehensions

Take advantage of comprehensions whenever possible:

  # Yes
  result = (item.name for item in array)

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

To filter:

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

To iterate over the keys and values of objects:

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

<a name="extending_native_objects"/>

Extending Native Objects

Do not modify native objects.

For example, do not modify Array.prototype to introduce Array#forEach.

<a name="exceptions"/>

Exceptions

Do not suppress exceptions.

<a name="annotations"/>

Annotations

Use annotations when necessary to describe a specific action that must be taken against the indicated block of code.

Write the annotation on the line immediately above the code that the annotation is describing.

The annotation keyword should be followed by a colon and a space, and a descriptive note.

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

If multiple lines are required by the description, indent subsequent lines with two spaces:

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

Annotation types:

  • TODO: describe missing functionality that should be added at a later date
  • FIXME: describe broken code that must be fixed
  • OPTIMIZE: describe code that is inefficient and may become a bottleneck
  • HACK: describe the use of a questionable (or ingenious) coding practice
  • REVIEW: describe code that should be reviewed to confirm implementation

If a custom annotation is required, the annotation should be documented in the project's README.

<a name="miscellaneous"/>

Miscellaneous

and is preferred over &&.

or is preferred over ||.

is is preferred over ==.

isnt is preferred over !=.

not is preferred over !.

or= should be used when possible:

temp or= {} # Yes
temp = temp || {} # No

Prefer shorthand notation (::) for accessing an object's prototype:

Array::slice # Yes
Array.prototype.slice # No

Prefer @property over this.property.

return @property # Yes
return this.property # No

However, avoid the use of standalone @:

return this # Yes
return @ # No

Avoid return where not required, unless the explicit return increases clarity.

Use splats (...) when working with functions that accept variable numbers of arguments:

console.log args... # Yes

(a, b, c, rest...) -> # Yes
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市伤锚,隨后出現(xiàn)的幾起案子趋艘,更是在濱河造成了極大的恐慌传睹,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钞艇,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)吮龄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)咆疗,“玉大人漓帚,你說我怎么就攤上這事∥绱牛” “怎么了尝抖?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵毡们,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我昧辽,道長(zhǎng)衙熔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任搅荞,我火速辦了婚禮红氯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘咕痛。我一直安慰自己痢甘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布茉贡。 她就那樣靜靜地躺著塞栅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪腔丧。 梳的紋絲不亂的頭發(fā)上放椰,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音愉粤,去河邊找鬼庄敛。 笑死,一個(gè)胖子當(dāng)著我的面吹牛科汗,可吹牛的內(nèi)容都是我干的藻烤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼头滔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼怖亭!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起坤检,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤兴猩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后早歇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體倾芝,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年箭跳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了晨另。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谱姓,死狀恐怖借尿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤路翻,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布狈癞,位于F島的核電站,受9級(jí)特大地震影響茂契,放射性物質(zhì)發(fā)生泄漏蝶桶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一掉冶、第九天 我趴在偏房一處隱蔽的房頂上張望莫瞬。 院中可真熱鬧,春花似錦郭蕉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至获询,卻和暖如春涨岁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吉嚣。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工梢薪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人尝哆。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓秉撇,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親秋泄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子琐馆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容