0%

Airbnb JavaScript Style Guide (2)

A mostly reasonable approach to JavaScript
一个最讲道理的JavaScript方法论

Modules 模块

  • [10.1] Always use modules (import/export) over a non-standard module system. You can always transpile to your preferred module system.
    在非标准模块系统里总是使用模块 (import/export) 。你可以总是使用你喜欢的反编译系统。

    Why? Modules are the future, let’s start using the future now.
    为什么?模块面向未来,让我们开始使用未来的工具吧。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // bad
    const AirbnbStyleGuide = require('./AirbnbStyleGuide');
    module.exports = AirbnbStyleGuide.es6;

    // ok
    import AirbnbStyleGuide from './AirbnbStyleGuide';
    export default AirbnbStyleGuide.es6;

    // best
    import { es6 } from './AirbnbStyleGuide';
    export default es6;
  • [10.2] Do not use wildcard imports.
    不要使用通配符引入

    Why? This makes sure you have a single default export.
    为什么? 这个可以保证你有单个默认的输出。

    1
    2
    3
    4
    5
    // bad
    import * as AirbnbStyleGuide from './AirbnbStyleGuide';

    // good
    import AirbnbStyleGuide from './AirbnbStyleGuide';
  • [10.3] And do not export directly from an import.
    不要导入的时候直接导出。

    Why? Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent.
    为什么?尽管一行很简洁,但是有一个清晰的导入方式和一个清晰的导出让它们更一致。

    1
    2
    3
    4
    5
    6
    7
    8
    // bad
    // filename es6.js
    export { es6 as default } from './AirbnbStyleGuide';

    // good
    // filename es6.js
    import { es6 } from './AirbnbStyleGuide';
    export default es6;
  • [10.4] Only import from a path in one place.
    eslint: no-duplicate-imports
    一个路径只在一个地方引入。

    Why? Having multiple lines that import from the same path can make code harder to maintain.
    为什么?有多行的引入可能导致代码难以维护。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // bad
    import foo from 'foo';
    // … some other imports … //
    import { named1, named2 } from 'foo';

    // good
    import foo, { named1, named2 } from 'foo';

    // good
    import foo, {
    named1,
    named2,
    } from 'foo';
  • [10.5] Do not export mutable bindings.
    eslint: import/no-mutable-exports
    可变值不要导出。

    Why? Mutation should be avoided in general, but in particular when exporting mutable bindings. While this technique may be needed for some special cases, in general, only constant references should be exported.
    为什么?变化一般情况下都应该被避免,尤其是导出可变的绑定值。尽管某些特殊情况需要可变绑定这个技术,但是一般情况下只有不可变引用可以导出。

    1
    2
    3
    4
    5
    6
    7
    // bad
    let foo = 3;
    export { foo };

    // good
    const foo = 3;
    export { foo };
  • [10.6] In modules with a single export, prefer default export over named export.
    eslint: import/prefer-default-export
    模块内有一个单独的导出,通过名字导出更好。

    1
    2
    3
    4
    5
    // bad
    export function foo() {}

    // good
    export default function foo() {}
  • [10.7] Put all imports above non-import statements.
    eslint: import/first
    把所有的 import 放在非 import 语句之前。

    Why? Since imports are hoisted, keeping them all at the top prevents surprising behavior.
    为什么?尽管import 会变量提升,但是保持他们在头部可以防止奇怪的行为。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // bad
    import foo from 'foo';
    foo.init();

    import bar from 'bar';

    // good
    import foo from 'foo';
    import bar from 'bar';

    foo.init();
  • [10.8] Multiline imports should be indented just like multiline array and object literals.
    多行引入应该缩进成多行数组和对象的语法一样。

    Why? The curly braces follow the same indentation rules as every other curly brace block in the style guide, as do the trailing commas.
    为什么?这个花括号遵守和其他所有花括号的语法规则一样的缩进规则,也同样应该留下末尾的逗号。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // bad
    import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';

    // good
    import {
    longNameA,
    longNameB,
    longNameC,
    longNameD,
    longNameE,
    } from 'path';
  • [10.9] Disallow Webpack loader syntax in module import statements.
    eslint: import/no-webpack-loader-syntax
    模块导入语句不允许 webpack loader 语法。

    Why? Since using Webpack syntax in the imports couples the code to a module bundler. Prefer using the loader syntax in webpack.config.js.
    为什么? 使用 webpack 的语法在导入语句让模块 bundler 的代码加倍了。更推荐在在webpack.config.js里面使用 loader 语法。

    1
    2
    3
    4
    5
    6
    7
    // bad
    import fooSass from 'css!sass!foo.scss';
    import barCss from 'style!css!bar.css';

    // good
    import fooSass from 'foo.scss';
    import barCss from 'bar.css';

Iterators and Generators 迭代器&生成器

  • [11.1] Don’t use iterators. Prefer JavaScript’s higher-order functions instead of loops like for-in or for-of. eslint: no-iterator no-restricted-syntax
    别用迭代器。推荐 JS 更高阶的函数而不是循环,如for-infor-of

    Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side effects.
    为什么? 这样强制执行不可变原则。处理返回值的纯函数比推断副作用要容易。

    Use map() / every() / filter() / find() / findIndex() / reduce() / some() / … to iterate over arrays, and Object.keys() / Object.values() / Object.entries() to produce arrays so you can iterate over objects.
    map() / every() / filter() / find() / findIndex() / reduce() / some() / … 来迭代数组,用 Object.keys() / Object.values() / Object.entries() 来生成用来迭代对象的数组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    const numbers = [1, 2, 3, 4, 5];

    // bad
    let sum = 0;
    for (let num of numbers) {
    sum += num;
    }
    sum === 15;

    // good
    let sum = 0;
    numbers.forEach((num) => {
    sum += num;
    });
    sum === 15;

    // best (use the functional force)
    const sum = numbers.reduce((total, num) => total + num, 0);
    sum === 15;

    // bad
    const increasedByOne = [];
    for (let i = 0; i < numbers.length; i++) {
    increasedByOne.push(numbers[i] + 1);
    }

    // good
    const increasedByOne = [];
    numbers.forEach((num) => {
    increasedByOne.push(num + 1);
    });

    // best (keeping it functional)
    const increasedByOne = numbers.map(num => num + 1);
  • [11.2] Don’t use generators for now.
    现在别用生成器。

    Why? They don’t transpile well to ES5.
    为什么?他们现在很难被编译成 ES5。

  • 11.3 If you must use generators, or if you disregard our advice, make sure their function signature is spaced properly. eslint: generator-star-spacing
    如果你非要用生成器,或者你无视我们的建议,确保他们的函数签名是空格使用恰当。

    Why? function and * are part of the same conceptual keyword - * is not a modifier for function, function* is a unique construct, different from function.
    为什么?function* 是概念上关键词的一部分,* 不是一个队function的修改者, function* 是一个和 function 不同的特殊构造器。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    // bad
    function * foo() {
    // ...
    }

    // bad
    const bar = function * () {
    // ...
    };

    // bad
    const baz = function *() {
    // ...
    };

    // bad
    const quux = function*() {
    // ...
    };

    // bad
    function*foo() {
    // ...
    }

    // bad
    function *foo() {
    // ...
    }

    // very bad
    function
    *
    foo() {
    // ...
    }

    // very bad
    const wat = function
    *
    () {
    // ...
    };

    // good
    function* foo() {
    // ...
    }

    // good
    const foo = function* () {
    // ...
    };

Properties 属性

  • [12.1] Use dot notation when accessing properties. eslint: dot-notation jscs: requireDotNotation
    存取属性使用点符号。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const luke = {
    jedi: true,
    age: 28,
    };

    // bad
    const isJedi = luke['jedi'];

    // good
    const isJedi = luke.jedi;
  • [12.2] Use bracket notation [] when accessing properties with a variable.
    存取变量属性的时候使用方括号符号。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const luke = {
    jedi: true,
    age: 28,
    };

    function getProp(prop) {
    return luke[prop];
    }

    const isJedi = getProp('jedi');
  • [12.3] Use exponentiation operator ** when calculating exponentiations. eslint: no-restricted-properties.
    使用乘方符号当需要计算幂次方的时候。

    1
    2
    3
    4
    5
    // bad
    const binary = Math.pow(2, 10);

    // good
    const binary = 2 ** 10;

Variables 变量

  • [13.1] Always use const or let to declare variables. Not doing so will result in global variables. We want to avoid polluting the global namespace. Captain Planet warned us of that. eslint: no-undef prefer-const
    总是使用 const 或者 let 来声明变量。不这么做会产生全局变量。我们想避免污染全局命名空间。地球超人那样警告了我们。

    1
    2
    3
    4
    5
    // bad
    superPower = new SuperPower();

    // good
    const superPower = new SuperPower();
  • [13.2] Use one const or let declaration per variable. eslint: one-var jscs: disallowMultipleVarDecl
    每个变量单独使用声明关键词。

    Why? It’s easier to add new variable declarations this way, and you never have to worry about swapping out a ; for a , or introducing punctuation-only diffs. You can also step through each declaration with the debugger, instead of jumping through all of them at once.
    为什么?这样更容易加一个新的变量声明,你不需要担心交换分号、逗号或者其他符号之类的问题。你还可以调试的时候步进调试而不是一次性跳过所有。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // bad
    const items = getItems(),
    goSportsTeam = true,
    dragonball = 'z';

    // bad
    // (compare to above, and try to spot the mistake)
    const items = getItems(),
    goSportsTeam = true;
    dragonball = 'z';

    // good
    const items = getItems();
    const goSportsTeam = true;
    const dragonball = 'z';
  • [13.3]Group all your consts and then group all your lets.
    const 和 let 要进行分组。

    Why? This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables.
    为什么?当你需要给一个依赖先前变量的变量赋值的时候,这是很有用的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // bad
    let i, len, dragonball,
    items = getItems(),
    goSportsTeam = true;

    // bad
    let i;
    const items = getItems();
    let dragonball;
    const goSportsTeam = true;
    let len;

    // good
    const goSportsTeam = true;
    const items = getItems();
    let dragonball;
    let i;
    let length;
  • [13.4] Assign variables where you need them, but place them in a reasonable place.
    在你需要的地方给变量赋值,但是把他们放在符合逻辑的地方。

    Why? let and const are block scoped and not function scoped.
    为什么?let and const 是块作用域而不是函数作用域。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    // bad - unnecessary function call
    function checkName(hasName) {
    const name = getName();

    if (hasName === 'test') {
    return false;
    }

    if (name === 'test') {
    this.setName('');
    return false;
    }

    return name;
    }

    // good
    function checkName(hasName) {
    if (hasName === 'test') {
    return false;
    }

    const name = getName();

    if (name === 'test') {
    this.setName('');
    return false;
    }

    return name;
    }
  • [13.5] Don’t chain variable assignments.
    不要链式赋值。

    Why? Chaining variable assignments creates implicit global variables.
    为什么?链式赋值会创造隐式全局变量。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // bad
    (function example() {
    // JavaScript interprets this as
    // let a = ( b = ( c = 1 ) );
    // The let keyword only applies to variable a; variables b and c become
    // global variables.
    let a = b = c = 1;
    }());

    console.log(a); // throws ReferenceError
    console.log(b); // 1
    console.log(c); // 1

    // good
    (function example() {
    let a = 1;
    let b = a;
    let c = a;
    }());

    console.log(a); // throws ReferenceError
    console.log(b); // throws ReferenceError
    console.log(c); // throws ReferenceError

    // the same applies for `const`
  • [13.6] Avoid using unary increments and decrements (++, –). eslint no-plusplus
    避免使用单目增减运算符。

    Why? Per the eslint documentation, unary increment and decrement statements are subject to automatic semicolon insertion and can cause silent errors with incrementing or decrementing values within an application. It is also more expressive to mutate your values with statements like num += 1 instead of num++ or num ++. Disallowing unary increment and decrement statements also prevents you from pre-incrementing/pre-decrementing values unintentionally which can also cause unexpected behavior in your programs.
    为什么?任何一个 eslint 的文档,单目运算符会自动添加分号,可以造成隐式错误。使用 num += 1 这种改变变量值的语句更有表现力。不允许单目运算符还能防止预期之外的预增值或者预减值,这科恩给你造成预期之外的结果。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    // bad

    const array = [1, 2, 3];
    let num = 1;
    num++;
    --num;

    let sum = 0;
    let truthyCount = 0;
    for (let i = 0; i < array.length; i++) {
    let value = array[i];
    sum += value;
    if (value) {
    truthyCount++;
    }
    }

    // good

    const array = [1, 2, 3];
    let num = 1;
    num += 1;
    num -= 1;

    const sum = array.reduce((a, b) => a + b, 0);
    const truthyCount = array.filter(Boolean).length;

Hoisting 变量提升

  • [14.1] var declarations get hoisted to the top of their scope, their assignment does not. const and let declarations are blessed with a new concept called Temporal Dead Zones (TDZ). It’s important to know why typeof is no longer safe.
    var 的声明会被提升到作用域的头部,但是赋值不会。const 和 let 声明受益于一个新的概念TDZ。了解一下为什么 typeof 是不安全的很重要。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    // we know this wouldn’t work (assuming there
    // is no notDefined global variable)
    function example() {
    console.log(notDefined); // => throws a ReferenceError
    }

    // creating a variable declaration after you
    // reference the variable will work due to
    // variable hoisting. Note: the assignment
    // value of `true` is not hoisted.
    function example() {
    console.log(declaredButNotAssigned); // => undefined
    var declaredButNotAssigned = true;
    }

    // the interpreter is hoisting the variable
    // declaration to the top of the scope,
    // which means our example could be rewritten as:
    function example() {
    let declaredButNotAssigned;
    console.log(declaredButNotAssigned); // => undefined
    declaredButNotAssigned = true;
    }

    // using const and let
    function example() {
    console.log(declaredButNotAssigned); // => throws a ReferenceError
    console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
    const declaredButNotAssigned = true;
    }
  • [14.2] Anonymous function expressions hoist their variable name, but not the function assignment.
    匿名函数表达式提升他们的变量名,但是不提升函数赋值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function example() {
    console.log(anonymous); // => undefined

    anonymous(); // => TypeError anonymous is not a function

    var anonymous = function () {
    console.log('anonymous function expression');
    };
    }
  • [14.3] Named function expressions hoist the variable name, not the function name or the function body.
    实名函数表达式提升变量名,不提升函数名和函数主体。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    function example() {
    console.log(named); // => undefined

    named(); // => TypeError named is not a function

    superPower(); // => ReferenceError superPower is not defined

    var named = function superPower() {
    console.log('Flying');
    };
    }

    // the same is true when the function name
    // is the same as the variable name.
    function example() {
    console.log(named); // => undefined

    named(); // => TypeError named is not a function

    var named = function named() {
    console.log('named');
    };
    }
  • [14.4] Function declarations hoist their name and the function body.
    函数声明提升名字和函数主体

    1
    2
    3
    4
    5
    6
    7
    function example() {
    superPower(); // => Flying

    function superPower() {
    console.log('Flying');
    }
    }
  • For more information refer to JavaScript Scoping & Hoisting by Ben Cherry.

  • 了解更多💩特性上这个网站JavaScript Scoping & Hoisting by Ben Cherry.

Comparison Operators & Equality 比较符号&相等判断

  • [15.1] Use === and !== over == and !=. eslint: eqeqeq
    使用三等号三不等,不用双等双不等。

  • [15.2] Conditional statements such as the if statement evaluate their expression using coercion with the ToBoolean abstract method and always follow these simple rules:
    条件语句比如 if 强制使用 toBoolean 抽象方法来判断值:

    • Objects evaluate to true
    • Undefined evaluates to false
    • Null evaluates to false
    • Booleans evaluate to the value of the boolean
    • Numbers evaluate to false if +0, -0, or NaN, otherwise true
    • Strings evaluate to false if an empty string '', otherwise true
    1
    2
    3
    4
    if ([0] && []) {
    // true
    // an array (even an empty one) is an object, objects will evaluate to true
    }
  • [15.3] Use shortcuts for booleans, but explicit comparisons for strings and numbers.
    使用布尔值简写,但是严格的比较字符串和数字。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    // bad
    if (isValid === true) {
    // ...
    }

    // good
    if (isValid) {
    // ...
    }

    // bad
    if (name) {
    // ...
    }

    // good
    if (name !== '') {
    // ...
    }

    // bad
    if (collection.length) {
    // ...
    }

    // good
    if (collection.length > 0) {
    // ...
    }
  • [15.4] For more information see Truth Equality and JavaScript by Angus Croll.
    更多信息查看这个Truth Equality and JavaScript by Angus Croll.

  • [15.5] Use braces to create blocks in case and default clauses that contain lexical declarations (e.g. let, const, function, and class). eslint: no-case-declarations
    用花括号把包含字符定义的 case or default 子句起来

    Why? Lexical declarations are visible in the entire switch block but only get initialized when assigned, which only happens when its case is reached. This causes problems when multiple case clauses attempt to define the same thing.
    为什么?字符声明对整个 switch 块可见,但是只有在初始化的时候可以复制,只在 case 到达的时候发生,这可能在多个子句定义同样的东西的时候带来问题。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    // bad
    switch (foo) {
    case 1:
    let x = 1;
    break;
    case 2:
    const y = 2;
    break;
    case 3:
    function f() {
    // ...
    }
    break;
    default:
    class C {}
    }

    // good
    switch (foo) {
    case 1: {
    let x = 1;
    break;
    }
    case 2: {
    const y = 2;
    break;
    }
    case 3: {
    function f() {
    // ...
    }
    break;
    }
    case 4:
    bar();
    break;
    default: {
    class C {}
    }
    }
  • [15.6] Ternaries should not be nested and generally be single line expressions. eslint: no-nested-ternary
    三目运算不应该嵌套,一般应该一行一个。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // bad
    const foo = maybe1 > maybe2
    ? "bar"
    : value1 > value2 ? "baz" : null;

    // better
    const maybeNull = value1 > value2 ? 'baz' : null;

    const foo = maybe1 > maybe2
    ? 'bar'
    : maybeNull;

    // best
    const maybeNull = value1 > value2 ? 'baz' : null;

    const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
  • [15.7] Avoid unneeded ternary statements. eslint: no-unneeded-ternary
    避免不必要的三目运算。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // bad
    const foo = a ? a : b;
    const bar = c ? true : false;
    const baz = c ? false : true;

    // good
    const foo = a || b;
    const bar = !!c;
    //两个感叹号表示某个元素是否存在。 可以理解为强制转 boolean
    //还有~~是下取整
    const baz = !c;

Blocks 块

  • [16.1] Use braces with all multi-line blocks.
    使用多行的块用花括号包起来。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // bad
    if (test)
    return false;

    // good
    if (test) return false;

    // good
    if (test) {
    return false;
    }

    // bad
    function foo() { return false; }

    // good
    function bar() {
    return false;
    }
  • [16.2] If you’re using multi-line blocks with if and else, put else on the same line as your if block’s closing brace. eslint: brace-style jscs: disallowNewlineBeforeBlockStatements
    如果你使用含 if else 的多行块,把上一个右括号和下一个左括号和关键字放一行。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // bad
    if (test) {
    thing1();
    thing2();
    }
    else {
    thing3();
    }

    // good
    if (test) {
    thing1();
    thing2();
    } else {
    thing3();
    }

Control Statements 控制语句

  • [17.1] In case your control statement (if, while etc.) gets too long or exceeds the maximum line length, each (grouped) condition could be put into a new line. It’s up to you whether the logical operator should begin or end the line.
    万一你的控制语句(如 if else)太长了或者超过了最大单行长度限制,每个条件应该单独放一行。逻辑符号放行首或行尾你可以自己定。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    // bad
    if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
    thing1();
    }

    // bad
    if (foo === 123 &&
    bar === 'abc') {
    thing1();
    }

    // bad
    if (foo === 123
    && bar === 'abc') {
    thing1();
    }

    // good
    if (
    (foo === 123 || bar === "abc") &&
    doesItLookGoodWhenItBecomesThatLong() &&
    isThisReallyHappening()
    ) {
    thing1();
    }

    // good
    if (foo === 123 && bar === 'abc') {
    thing1();
    }

    // good
    if (
    foo === 123 &&
    bar === 'abc'
    ) {
    thing1();
    }

    // good
    if (
    foo === 123
    && bar === 'abc'
    ) {
    thing1();
    }

Comments 注释

  • [18.1] Use /** ... */ for multi-line comments.
    使用/** ... */来做多行注释。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // bad
    // make() returns a new element
    // based on the passed in tag name
    //
    // @param {String} tag
    // @return {Element} element
    function make(tag) {

    // ...

    return element;
    }

    // good
    /**
    * make() returns a new element
    * based on the passed-in tag name
    */
    function make(tag) {

    // ...

    return element;
    }
  • [18.2] Use // for single line comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment unless it’s on the first line of a block.
    使用 // 来单行注释。把单行注释放在新行,和要注释的代码的上方。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    // bad
    const active = true; // is current tab

    // good
    // is current tab
    const active = true;

    // bad
    function getType() {
    console.log('fetching type...');
    // set the default type to 'no type'
    const type = this.type || 'no type';

    return type;
    }

    // good
    function getType() {
    console.log('fetching type...');

    // set the default type to 'no type'
    const type = this.type || 'no type';

    return type;
    }

    // also good
    function getType() {
    // set the default type to 'no type'
    const type = this.type || 'no type';

    return type;
    }
  • [18.3] Start all comments with a space to make it easier to read. eslint: spaced-comment
    所有的评论先打一个空格,方便阅读。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    // bad
    //is current tab
    const active = true;

    // good
    // is current tab
    const active = true;

    // bad
    /**
    *make() returns a new element
    *based on the passed-in tag name
    */
    function make(tag) {

    // ...

    return element;
    }

    // good
    /**
    * make() returns a new element
    * based on the passed-in tag name
    */
    function make(tag) {

    // ...

    return element;
    }
  • [18.4] Prefixing your comments with FIXME or TODO helps other developers quickly understand if you’re pointing out a problem that needs to be revisited, or if you’re suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions are FIXME: -- need to figure this out or TODO: -- need to implement.
    FIXMETODO当前缀的评论帮助其他的开发者迅速理解你指出了一个需要重访的问题,或者你推荐一个需要被实现的解决方案。这些不同于普通评论,因为他们可以提出行动要求。功能如:FIXME: -- need to figure this out or TODO: -- need to implement.

  • [18.5] Use // FIXME: to annotate problems.
    使用 // FIXME: 来注释问题

    1
    2
    3
    4
    5
    6
    7
    8
    class Calculator extends Abacus {
    constructor() {
    super();

    // FIXME: shouldn’t use a global here
    total = 0;
    }
    }
  • [18.6] Use // TODO: to annotate solutions to problems.
    使用 // TODO: 来注释需要解决的问题。

    1
    2
    3
    4
    5
    6
    7
    8
    class Calculator extends Abacus {
    constructor() {
    super();

    // TODO: total should be configurable by an options param
    this.total = 0;
    }
    }

Whitespace 空格

  • [19.1] Use soft tabs (space character) set to 2 spaces. eslint: indent jscs: validateIndentation
    使用 软TAB/空格 设置两个空格。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // bad
    function foo() {
    ∙∙∙∙let name;
    }

    // bad
    function bar() {
    let name;
    }

    // good
    function baz() {
    ∙∙let name;
    }
  • [19.2] Place 1 space before the leading brace. eslint: space-before-blocks jscs: requireSpaceBeforeBlockStatements
    花括号前使用一个空格。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // bad
    function test(){
    console.log('test');
    }

    // good
    function test() {
    console.log('test');
    }

    // bad
    dog.set('attr',{
    age: '1 year',
    breed: 'Bernese Mountain Dog',
    });

    // good
    dog.set('attr', {
    age: '1 year',
    breed: 'Bernese Mountain Dog',
    });
  • [19.3] Place 1 space before the opening parenthesis in control statements (if, while etc.). Place no space between the argument list and the function name in function calls and declarations. eslint: keyword-spacing jscs: requireSpaceAfterKeywords
    控制语句的左圆括号前放一个空格。参数列表之间、函数调用和声明里的函数名不要放空格。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // bad
    if(isJedi) {
    fight ();
    }

    // good
    if (isJedi) {
    fight();
    }

    // bad
    function fight () {
    console.log ('Swooosh!');
    }

    // good
    function fight() {
    console.log('Swooosh!');
    }
  • [19.4] Set off operators with spaces. eslint: space-infix-ops jscs: requireSpaceBeforeBinaryOperators, requireSpaceAfterBinaryOperators
    操作符用空格分开。

    1
    2
    3
    4
    5
    // bad
    const x=y+5;

    // good
    const x = y + 5;
  • [19.5] End files with a single newline character. eslint: eol-last
    文件末尾来一个新行。

    1
    2
    3
    4
    // bad
    import { es6 } from './AirbnbStyleGuide';
    // ...
    export default es6;
    1
    2
    3
    4
    5
    // bad
    import { es6 } from './AirbnbStyleGuide';
    // ...
    export default es6;↵

    1
    2
    3
    4
    // good
    import { es6 } from './AirbnbStyleGuide';
    // ...
    export default es6;↵
  • [19.6] Use indentation when making long method chains (more than 2 method chains). Use a leading dot, which emphasizes that the line is a method call, not a new statement. eslint: newline-per-chained-call no-whitespace-before-property
    长的方法调用链应该使用缩进。使用一个前导的点,强调这个行是一个方法调用,不是声明。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    // bad
    $('#items').find('.selected').highlight().end().find('.open').updateCount();

    // bad
    $('#items').
    find('.selected').
    highlight().
    end().
    find('.open').
    updateCount();

    // good
    $('#items')
    .find('.selected')
    .highlight()
    .end()
    .find('.open')
    .updateCount();

    // bad
    const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
    .attr('width', (radius + margin) * 2).append('svg:g')
    .attr('transform', `translate(${radius + margin},${radius + margin})`)
    .call(tron.led);

    // good
    const leds = stage.selectAll('.led')
    .data(data)
    .enter().append('svg:svg')
    .classed('led', true)
    .attr('width', (radius + margin) * 2)
    .append('svg:g')
    .attr('transform', `translate(${radius + margin},${radius + margin})`)
    .call(tron.led);

    // good
    const leds = stage.selectAll('.led').data(data);
  • [19.7] Leave a blank line after blocks and before the next statement. jscs: requirePaddingNewLinesAfterBlocks
    块后面应该加一个空行再写其他句子。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    // bad
    if (foo) {
    return bar;
    }
    return baz;

    // good
    if (foo) {
    return bar;
    }

    return baz;

    // bad
    const obj = {
    foo() {
    },
    bar() {
    },
    };
    return obj;

    // good
    const obj = {
    foo() {
    },

    bar() {
    },
    };

    return obj;

    // bad
    const arr = [
    function foo() {
    },
    function bar() {
    },
    ];
    return arr;

    // good
    const arr = [
    function foo() {
    },

    function bar() {
    },
    ];

    return arr;
  • [19.8] Do not pad your blocks with blank lines. eslint: padded-blocks jscs: disallowPaddingNewlinesInBlocks
    不要用空行来填补块。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    // bad
    function bar() {

    console.log(foo);

    }

    // also bad
    if (baz) {

    console.log(qux);
    } else {
    console.log(foo);

    }

    // good
    function bar() {
    console.log(foo);
    }

    // good
    if (baz) {
    console.log(qux);
    } else {
    console.log(foo);
    }
  • [19.9] Do not add spaces inside parentheses. eslint: space-in-parens jscs: disallowSpacesInsideParentheses
    圆括号内侧不要加空格。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // bad
    function bar( foo ) {
    return foo;
    }

    // good
    function bar(foo) {
    return foo;
    }

    // bad
    if ( foo ) {
    console.log(foo);
    }

    // good
    if (foo) {
    console.log(foo);
    }
  • [19.10] Do not add spaces inside brackets. eslint: array-bracket-spacing jscs: disallowSpacesInsideArrayBrackets
    方括号内侧不要加空格。

    1
    2
    3
    4
    5
    6
    7
    // bad
    const foo = [ 1, 2, 3 ];
    console.log(foo[ 0 ]);

    // good
    const foo = [1, 2, 3];
    console.log(foo[0]);
  • [19.11] Add spaces inside curly braces. eslint: object-curly-spacing jscs: requireSpacesInsideObjectBrackets
    花括号内侧加空格。

    1
    2
    3
    4
    5
    // bad
    const foo = {clark: 'kent'};

    // good
    const foo = { clark: 'kent' };
  • [19.12] Avoid having lines of code that are longer than 100 characters (including whitespace). Note: per above, long strings are exempt from this rule, and should not be broken up. eslint: max-len jscs: maximumLineLength
    避免一个行超过100个字符。注意,所有的长字符串都不应该超过这个限制。应该把他们分开。

    Why? This ensures readability and maintainability.
    为什么?这个包装可读性和可维护性。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // bad
    const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy;

    // bad
    $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.'));

    // good
    const foo = jsonData
    && jsonData.foo
    && jsonData.foo.bar
    && jsonData.foo.bar.baz
    && jsonData.foo.bar.baz.quux
    && jsonData.foo.bar.baz.quux.xyzzy;

    // good
    $.ajax({
    method: 'POST',
    url: 'https://airbnb.com/',
    data: { name: 'John' },
    })
    .done(() => console.log('Congratulations!'))
    .fail(() => console.log('You have failed this city.'));