Skip to content

✅ Waimai Business Platform javascript style guide(based on airbnb/javascript)

License

Notifications You must be signed in to change notification settings

clancyz/wm-bp-javascript

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Waimai Business Platform JavaScript Style Guide() {

基于Airbnb JavaScript Style Guide的javascript代码规范

本文是完整代码规范建议子集,提及内容为eslint可检查部分。

补充规范:

  1. JSX相关规范
  2. React相关规范
  3. React Native相关规范

IDE/构建工具/格式化工具配置请看配置文档

本文规则分为三类:

  • 强制: 不符合规范 => eslint error
  • 建议 / warn: 不符合规范 => eslint warn 警告提示
  • 建议 / off: 建议你以这样的方式进行 => eslint off 不进行检查

建议通读完整规范,获得更好的代码书写指导建议。

修改的部分会以[modified]标注,无此说明的即与原文规约相同。

目录

  1. 对象
  2. 数组
  3. 解构
  4. 字符串
  5. 函数
  6. 箭头函数
  7. 构造函数
  8. 模块
  9. Iterators & Generators
  10. 属性
  11. 变量
  12. 提升
  13. 比较运算符 & 等号
  14. 代码块
  15. 注释
  16. 空白
  17. 逗号
  18. 分号
  19. 类型转换
  20. 命名规则
  21. 存取器
  22. 事件
  23. jQuery
  24. ECMAScript 5 兼容性
  25. ECMAScript 6 编码规范

引用

  • 2.1 [强制] 对所有的引用使用 const ;不要使用 var eslint: prefer-const, no-const-assign

    为什么?这能确保你无法对引用重新赋值,也不会导致出现 bug 或难以理解。

    // bad
    var a = 1;
    var b = 2;
    
    // good
    const a = 1;
    const b = 2;
  • 2.2 [强制] 如果你一定需要可变动的引用,使用 let 代替 var eslint: no-var jscs: disallowVar

    为什么?因为 let 是块级作用域,而 var 是函数作用域。

    // bad
    var count = 1;
    if (true) {
        count += 1;
    }
    
    // good, use the let.
    let count = 1;
    if (true) {
        count += 1;
    }

⬆ 返回目录

对象

  • 3.1 [强制] 使用字面值创建对象。 eslint: no-new-object

    // bad
    const item = new Object();
    
    // good
    const item = {};

  • 3.4 [强制] 使用对象属性值的简写。 eslint: object-shorthand jscs: requireEnhancedObjectLiterals

    为什么?因为这样更短更有描述性。

    const lukeSkywalker = 'Luke Skywalker';
    
    // bad
    const obj = {
        lukeSkywalker: lukeSkywalker,
    };
    
    // good
    const obj = {
        lukeSkywalker,
    };
  • 3.6 [强制] 仅在对象属性有特殊符号时使用引号包裹。 eslint: quote-props jscs: disallowQuotedKeysInObjects

    为什么? 这样看上去更加易读,另外还能有相关的代码高亮,也容易被许多JS引擎优化。

    // bad
    const bad = {
    'foo': 3,
    'bar': 4,
    'data-blah': 5,
    };
    
    // good
    const good = {
    foo: 3,
    bar: 4,
    'data-blah': 5,
    };

⬆ 返回目录

数组

  • 4.1 [强制] 使用字面值创建数组。 eslint: no-array-constructor

    // bad
    const items = new Array();
    
    // good
    const items = [];

  • 4.5 [强制] 数组的相关方法使用return语句。如果函数体仅由一个带表达式且无副作用的语句组成,可以忽略return。 参考8.2. eslint: array-callback-return

    // good
    [1, 2, 3].map((x) => {
        const y = x + 1;
        return x * y;
    });
    
    // good
    [1, 2, 3].map(x => x + 1);
    
    // bad
    const flat = {};
    [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
        const flatten = memo.concat(item);
        flat[index] = flatten;
    });
    
    // good
    const flat = {};
    [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
        const flatten = memo.concat(item);
        flat[index] = flatten;
        return flatten;
    });
    
    // bad
    inbox.filter((msg) => {
        const { subject, author } = msg;
        if (subject === 'Mockingbird') {
        return author === 'Harper Lee';
        } else {
        return false;
        }
    });
    
    // good
    inbox.filter((msg) => {
        const { subject, author } = msg;
        if (subject === 'Mockingbird') {
        return author === 'Harper Lee';
        }
    
        return false;
    });

⬆ 返回目录

解构

Strings

  • 6.1 [强制] 字符串使用单引号 '' eslint: quotes jscs: validateQuoteMarks

    // bad
    const name = "Capt. Janeway";
    
    // good
    const name = 'Capt. Janeway';

  • 6.4 [modified][建议 / warn]程序化生成字符串时,使用模板字符串代替字符串连接。 eslint: prefer-template template-curly-spacing jscs: requireTemplateStrings

    为什么?模板字符串更为简洁,更具可读性。

    // bad
    function sayHi(name) {
        return 'How are you, ' + name + '?';
    }
    
    // bad
    function sayHi(name) {
        return ['How are you, ', name, '?'].join();
    }
    
    // good
    function sayHi(name) {
        return `How are you, ${name}?`;
    }

  • 6.4 [强制] 不要对字符串使用 eval(),会导致一系列问题。 eslint: no-eval

  • 6.5 [modified] [建议 / off] 不要对字符串使用不必要的escape操作。 eslint: no-useless-escape

    为什么? 反斜杠会影响可读性,仅在必须的时候使用它。

    // bad
    const foo = '\'this\' \i\s \"quoted\"';
    
    // good
    const foo = '\'this\' is "quoted"';
    const foo = `my name is '${name}'`;

⬆ 返回目录

函数

  • 7.1 [modified] [建议 / off] 使用具名函数代替函数声明。 eslint: func-style jscs: disallowFunctionDeclarations

    为什么?因为函数声明会把函数提升(hoisted), 这样易使函数在定义前被引用。这会影响可读性和可维护性。如果一个函数的定义很长或很复杂,会干扰对文件剩余部分的理解,更好的方式是将它抽象在它自己的模块中。别忘了给函数表达式命名 - 匿名函数会使得在错误调用栈中定位问题变得困难。(讨论)

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

  • 7.2 [强制] 对于立即调用(IIFE)的函数表达式,用括号包裹函数体。 eslint: wrap-iife jscs: requireParenthesesAroundIIFE

    为什么?立即调用函数是一个独立单元 - 用括号包裹函数体可以清晰地表达这一点。需要注意的是,在一个到处都是「模块」的世界,几乎从不需要IIFE。

    // 立即调用的函数 (IIFE)
    (function () {
    console.log('Welcome to the Internet. Please follow me.');
    }());
  • 7.3 [强制] 永远不要在一个非函数代码块(ifwhile 等)中声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但它们的解析表现不一致。 eslint: no-loop-func

  • 7.6 [modified][建议 / off] 不要使用 arguments。可以选择 rest 语法 ... 替代。 eslint: prefer-rest-params

    为什么?使用 ... 能明确你要传入的参数。另外 rest 参数是一个真正的数组,而 arguments 是一个类数组。

    // bad
    function concatenateAll() {
        const args = Array.prototype.slice.call(arguments);
        return args.join('');
    }
    
    // good
    function concatenateAll(...args) {
        return args.join('');
    }

  • 7.10 [强制] 永远不要使用Function构造函数来创建一个新函数。 eslint: no-new-func

    为什么?这种方式在分析字符串时与eval()类似,会带来各种问题。

    // bad
    var add = new Function('a', 'b', 'return a + b');
    
    // still bad
    var subtract = Function('a', 'b', 'return a - b');

  • 7.11 [强制] [强制] 在函数签名中使用空格。 eslint: space-before-function-paren space-before-blocks

    为什么?保持一致性是最佳实践, 另外如果在添加或删除名称时也不应增加/删除空格。

    // bad
    const f = function(){};
    const g = function (){};
    const h = function() {};
    
    // good
    const x = function () {};
    const y = function a() {};

  • 7.12 [强制] 永远不要改变(mutate)参数。 eslint: no-param-reassign

    为什么?对传入的参数进行操作会在原始调用带来不想要的变量副作用。

    // bad
    function f1(obj) {
        obj.key = 1;
    }
    
    // good
    function f2(obj) {
        const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
    }

  • 7.13 [强制] 永远不要对参数重新赋值(reassign)。 eslint: no-param-reassign

    为什么?对参数重新赋值会引起意料之外的行为,特别是对于arguments的访问。同时它会引起优化问题,特别在V8引擎中。

    // bad
    function f1(a) {
        a = 1;
        // ...
    }
    
    function f2(a) {
        if (!a) { a = 1; }
        // ...
    }
    
    // good
    function f3(a) {
        const b = a || 1;
        // ...
    }
    
    function f4(a = 1) {
        // ...
    }

  • 7.14 [modified][建议 / warn] 推荐使用展开运算符 ... 来调用可变参数的函数。 eslint: prefer-spread

    为什么?这样更加清晰,也不用提供上下文,而且把newapply 组合的方式也比较蛋疼。

    // bad
    const x = [1, 2, 3, 4, 5];
    console.log.apply(console, x);
    
    // good
    const x = [1, 2, 3, 4, 5];
    console.log(...x);
    
    // bad
    new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));
    
    // good
    new Date(...[2016, 8, 5]);

⬆ 返回目录

箭头函数

  • 8.1 [强制] 当你必须使用函数表达式(或传递一个匿名函数)时,使用箭头函数符号。 eslint: prefer-arrow-callback, arrow-spacing jscs: requireArrowFunctions

    为什么?因为箭头函数创造了新的一个 this 执行环境(译注:参考 Arrow functions - JavaScript | MDNES6 arrow functions, syntax and lexical scoping),通常情况下都能满足你的需求,而且这样的写法更为简洁。

    为什么不?如果你有一个相当复杂的函数,你或许可以把逻辑部分转移到一个函数声明上。

    // bad
    [1, 2, 3].map(function (x) {
      const y = x + 1;
      return x * y;
    });
    
    // good
    [1, 2, 3].map((x) => {
      const y = x + 1;
      return x * y;
    });
  • 8.2 [强制] 如果一个函数适合用一行写出并且只有一个参数,那就把花括号、圆括号和 return 都省略掉。如果不是,那就不要省略。 eslint: arrow-parens, arrow-body-style jscs: disallowParenthesesAroundArrowParam, requireShorthandArrowFunctions

    为什么?语法糖。在链式调用中可读性很高。

    // bad
    [1, 2, 3].map(number => {
      const nextNumber = number + 1;
      `A string containing the ${nextNumber}.`;
    });
    
    // good
    [1, 2, 3].map(number => `A string containing the ${number}.`);
    
    // good
    [1, 2, 3].map((number) => {
      const nextNumber = number + 1;
      return `A string containing the ${nextNumber}.`;
    });
    
    // good
    [1, 2, 3].map((number, index) => ({
      [index]: number,
    }));
    
    // 当有副作用时,不要隐式return
    function foo(callback) {
      const val = callback();
      if (val === true) {
        // Do something if callback returns true
      }
    }
    
    let bool = false;
    
    // bad
    foo(() => bool = true);
    
    // good
    foo(() => {
      bool = true;
    });

  • 8.4 [强制] 如果函数是单参数且不需要花括号{},则要省略掉括号。否则,始终用括号包裹参数,这样更加清晰,可读性也更好。 注:始终使用括号包裹参数也可以。 在eslint中使用 “always” option 或在jscs中不引入 disallowParenthesesAroundArrowParam。 eslint: arrow-parens jscs: disallowParenthesesAroundArrowParam

    为什么? 可以避免视觉上的混乱。

      // bad
      [1, 2, 3].map((x) => x * x);
    
      // good
      [1, 2, 3].map(x => x * x);
    
      // good
      [1, 2, 3].map(number => (
        `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
      ));
    
      // bad
      [1, 2, 3].map(x => {
        const y = x + 1;
        return x * y;
      });
    
      // good
      [1, 2, 3].map((x) => {
        const y = x + 1;
        return x * y;
      });

  • 8.5 [modified][建议 / off] 在箭头函数后避免使用 (<=, >=)这样的比较操作符。 eslint: no-confusing-arrow

    // bad
    const itemHeight = item => item.height > 256 ? item.largeSize : item.smallSize;
    
    // bad
    const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize;
    
    // good
    const itemHeight = item => (item.height > 256 ? item.largeSize : item.smallSize);
    
    // good
    const itemHeight = (item) => {
      const { height, largeSize, smallSize } = item;
      return height > 256 ? largeSize : smallSize;
    };

⬆ 返回目录

类和构造器

  • 9.1 [强制] 总是使用 class。避免直接操作 prototype

    为什么? 因为 class 语法更为简洁易读。

    // bad
    function Queue(contents = []) {
        this._queue = [...contents];
    }
    Queue.prototype.pop = function() {
        const value = this._queue[0];
        this._queue.splice(0, 1);
        return value;
    }
    
    
    // good
    class Queue {
        constructor(contents = []) {
        this._queue = [...contents];
        }
        pop() {
        const value = this._queue[0];
        this._queue.splice(0, 1);
        return value;
        }
    }

  • 9.5 [强制]如果没有显式声明,类都有个默认的构造器(constructor)。一个空或者仅代理了父类的构造函数是不必要的。 eslint: no-useless-constructor

    // bad
    class Jedi {
      constructor() {}
    
      getName() {
        return this.name;
      }
    }
    
    // bad
    class Rey extends Jedi {
      constructor(...args) {
        super(...args);
      }
    }
    
    // good
    class Rey extends Jedi {
      constructor(...args) {
        super(...args);
        this.name = 'Rey';
      }
    }

  • 9.6 [强制] 避免重复类成员。 eslint: no-dupe-class-members

    为什么? 重复声明类成员,默认最后一个优先级最高 - 几乎肯定是个bug。

    // bad
    class Foo {
      bar() { return 1; }
      bar() { return 2; }
    }
    
    // good
    class Foo {
      bar() { return 1; }
    }
    
    // good
    class Foo {
      bar() { return 2; }
    }

⬆ 返回目录

模块

  • 10.4 [强制] 避免从同一个位置重复import. eslint: no-duplicate-imports

    为什么? 这样会降低可维护性。

    // 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 [强制] 不要将可变量export。 eslint: import/no-mutable-exports

    为什么? 一般来说需要避免可变,特别是在export可变量时。虽然在某些特殊情况下需要这么做,但是一般来说只对常量的引用作export。

    // bad
    let foo = 3;
    export { foo };
    
    // good
    const foo = 3;
    export { foo };

  • 10.6 [强制] 只有单个export的模块,推荐使用default export而不是具名export。 eslint: import/prefer-default-export

    // bad
    export function foo() {}
    
    // good
    export default function foo() {}

  • 10.7 [强制] 把所有的import放在非import句式前。 eslint: import/first

    为什么? import存在提升(hoisted),把它们都置于文件顶部可以避免一些奇怪的行为。

    // bad
    import foo from 'foo';
    foo.init();
    
    import bar from 'bar';
    
    // good
    import foo from 'foo';
    import bar from 'bar';
    
    foo.init();

  • 10.9 [强制] 在import语句中不允许使用webpack loader语法。 eslint: import/no-webpack-loader-syntax

    为什么? 使用这种语法的代码对打包工具有强依赖。推荐在webpack.config.js中使用这类语法。

    // 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.3 [强制] 如果必须要使用generator, 那么要确保函数签名中使用正确的空格格式。 eslint: generator-star-spacing

    为什么? function* 都是概念上的关键字 - * 不是 function 的修饰符, function* 是一个统一结构体, 与function不同。

    // 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* () {
      // ...
    };

⬆ 返回目录

属性

  • 12.1 [建议 / warn] 使用 . 来访问对象的属性。 eslint: dot-notation jscs: requireDotNotation

    const luke = {
      jedi: true,
      age: 28,
    };
    
    // bad
    const isJedi = luke['jedi'];
    
    // good
    const isJedi = luke.jedi;

⬆ 返回目录

变量

  • 13.1 [强制] 一直使用 constlet 来声明变量,如果不这样做就会产生全局变量。 我们需要避免全局命名空间的污染。地球队长已经警告过我们了。(译注:全局,global 亦有全球的意思。地球队长的责任是保卫地球环境,所以他警告我们不要造成「全球」污染。)eslint: no-undef prefer-const

    // bad
    superPower = new SuperPower();
    
    // good
    const superPower = new SuperPower();
  • 13.2 [强制] 使用 constlet 声明每一个变量。 eslint: one-var jscs: disallowMultipleVarDecl

    为什么?增加新变量将变的更加容易,而且你永远不用再担心调换错 ;,

    // 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.5 [强制] 不要使用链式变量赋值.

    为什么?链式变量赋值会创建隐式全局变量。

    // bad
    (function example() {
      // JavaScript 解释器将这个语句解释为
      // let a = ( b = ( c = 1 ) );
      // let关键字仅对a生效,b和c变成了全局变量。
      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
    
    // 对于 `const`也是一样的。

  • 13.6 [modified][建议 / off] 避免使用一元增减运算符(++, --)。 eslint no-plusplus

    为什么? 根据eslint文档, 一元增减运算符会自动加入分号,在应用中会引起静默错误。使用num += 1 代替 num++num ++来变更值会显得更加易读。 不使用一元增减运算符也可以避免在不注意的情况下值做了预增减(pre-incrementing/pre-decrementing),也会导致预期外的错误。

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

⬆ 返回目录

代码块

  • 16.2 [强制] 如果通过 ifelse 使用多行代码块,把else另起一行。else 放在 if 代码块关闭括号的同一行。 eslint: brace-style jscs: disallowNewlineBeforeBlockStatements

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

⬆ 返回目录

控制语句

⬆ 返回目录

注释

  • 18.3 [强制] 所有注释开头加一个空格,增加可读性。 eslint: spaced-comment

    // 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;
    }

⬆ 返回目录

空格

  • 19.1 [强制] 使用 2 个空格作为缩进。 eslint: indent jscs: validateIndentation

    // bad
    function() {
    ∙∙∙∙const name;
    }
    
    // bad
    function() {
    ∙const name;
    }
    
    // good
    function() {
    ∙∙const name;
    }
  • 19.2 [强制] 在花括号前放一个空格。 eslint: space-before-blocks jscs: requireSpaceBeforeBlockStatements

    // 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 [强制] 在控制语句(ifwhile 等)的小括号前放一个空格。在函数调用及声明中,不在函数的参数列表前加空格。 eslint: keyword-spacing jscs: requireSpaceAfterKeywords

    // bad
    if(isJedi) {
      fight ();
    }
    
    // good
    if (isJedi) {
      fight();
    }
    
    // bad
    function fight () {
      console.log ('Swooosh!');
    }
    
    // good
    function fight() {
      console.log('Swooosh!');
    }
  • 19.4 [强制] 使用空格把运算符隔开。 eslint: space-infix-ops jscs: requireSpaceBeforeBinaryOperators, requireSpaceAfterBinaryOperators

    // bad
    const x=y+5;
    
    // good
    const x = y + 5;
  • 19.5 [强制] 在文件末尾插入一个空行。 eslint: eol-last

    // bad
    (function(global) {
      // ...stuff...
    })(this);
    // bad
    (function(global) {
      // ...stuff...
    })(this);
    
    // good
    (function(global) {
      // ...stuff...
    })(this);
  • 19.6 [强制] 在使用长方法链时进行缩进。使用前面的点 . 强调这是方法调用而不是新语句。 eslint: newline-per-chained-call no-whitespace-before-property

    译注:当链式超过4个之后使用换行。

    // 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').class('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);

  • 19.8 [强制]不要用代码块起始/结束位置加入空行。 eslint: padded-blocks jscs: disallowPaddingNewlinesInBlocks

    // 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 [强制] 不要在括号前后加入空格。 eslint: space-in-parens jscs: disallowSpacesInsideParentheses

    // 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.12 [强制] 避免一行超过100个字符。 备注:每个如上above的长字符串 可以不遵循这条规则。 eslint: max-len jscs: maximumLineLength

    为什么?这样做可以增加可读性和可维护性。

    // 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.'));

⬆ 返回目录

逗号

  • 20.1 [强制] 行首逗号:不需要。 eslint: comma-style jscs: requireCommaBeforeLineBreak

    // bad
    const story = [
        once
      , upon
      , aTime
    ];
    
    // good
    const story = [
      once,
      upon,
      aTime,
    ];
    
    // bad
    const hero = {
        firstName: 'Ada'
      , lastName: 'Lovelace'
      , birthYear: 1815
      , superPower: 'computers'
    };
    
    // good
    const hero = {
      firstName: 'Ada',
      lastName: 'Lovelace',
      birthYear: 1815,
      superPower: 'computers',
    };
  • 20.2 [强制] 增加结尾的逗号: 需要。 eslint: comma-dangle jscs: requireTrailingComma

    为什么? 这会让 git diffs 更干净。另外,像 babel 这样的转译器会移除结尾多余的逗号,也就是说你不必担心老旧浏览器的尾逗号问题

    // bad - git diff without trailing comma
    const hero = {
          firstName: 'Florence',
    -    lastName: 'Nightingale'
    +    lastName: 'Nightingale',
    +    inventorOf: ['coxcomb graph', 'modern nursing']
    }
    
    // good - git diff with trailing comma
    const hero = {
          firstName: 'Florence',
          lastName: 'Nightingale',
    +    inventorOf: ['coxcomb chart', 'modern nursing'],
    }
    
    // bad
    const hero = {
      firstName: 'Dana',
      lastName: 'Scully'
    };
    
    const heroes = [
      'Batman',
      'Superman'
    ];
    
    // good
    const hero = {
      firstName: 'Dana',
      lastName: 'Scully',
    };
    
    const heroes = [
      'Batman',
      'Superman',
    ];

⬆ 返回目录

分号

  • 21.1 [强制] 在语句末使用分号 eslint: semi jscs: requireSemicolons

    // bad
    (function() {
      const name = 'Skywalker'
      return name
    })()
    
    // good
    (() => {
      const name = 'Skywalker';
      return name;
    })();
    
    // good (防止函数在两个 IIFE 合并时被当成一个参数)
    ;(() => {
      const name = 'Skywalker';
      return name;
    })();

    Read more.

⬆ 返回目录

强制类型转换

  • 22.3 [强制] 对数字使用 parseInt 转换,并带上类型转换的基数。 eslint: radix

    const inputValue = '4';
    
    // bad
    const val = new Number(inputValue);
    
    // bad
    const val = +inputValue;
    
    // bad
    const val = inputValue >> 0;
    
    // bad
    const val = parseInt(inputValue);
    
    // good
    const val = Number(inputValue);
    
    // good
    const val = parseInt(inputValue, 10);

⬆ 返回目录

命名规则

  • 23.1 [modified][建议 / off]避免单字母命名。命名应语义化。 eslint: id-length

    // bad
    function q() {
      // ...stuff...
    }
    
    // good
    function query() {
      // ..stuff..
    }
  • 23.2 [强制] 使用驼峰式命名对象、函数和实例。 eslint: camelcase jscs: requireCamelCaseOrUpperCaseIdentifiers

    // bad
    const OBJEcttsssss = {};
    const this_is_my_object = {};
    function c() {}
    
    // good
    const thisIsMyObject = {};
    function thisIsMyFunction() {}
  • 23.3 [强制] 使用帕斯卡式命名构造函数或类。 eslint: new-cap jscs: requireCapitalizedConstructors

    // bad
    function user(options) {
      this.name = options.name;
    }
    
    const bad = new user({
      name: 'nope',
    });
    
    // good
    class User {
      constructor(options) {
        this.name = options.name;
      }
    }
    
    const good = new User({
      name: 'yup',
    });
  • 23.4 [modified][建议 / warn] 不要使用下划线 _ 结尾或开头来命名属性和方法。 eslint: no-underscore-dangle jscs: disallowDanglingUnderscores

    为什么? Javascript对属性或方法而言并没有「私有」的定义。虽然用大多人用下划线开头表示“私有”, 但是实际上这些方法是完全公有的,是公共API的一部分。这种方式会让开发者误认为修改不会影响到它,或者不需要测试。如果你需要一些“私有”定义,那么它们不应该这样显眼。

    // bad
    this.__firstName__ = 'Panda';
    this.firstName_ = 'Panda';
    this._firstName = 'Panda';
    
    // good
    this.firstName = 'Panda';
  • 23.5 [强制] 别保存 this 的引用。使用箭头函数或 Function#bind. jscs: disallowNodeTypes

    // bad
    function foo() {
      const self = this;
      return function() {
        console.log(self);
      };
    }
    
    // bad
    function foo() {
      const that = this;
      return function() {
        console.log(that);
      };
    }
    
    // good
    function foo() {
      return () => {
        console.log(this);
      };
    }

⬆ 返回目录

存取器

⬆ 返回目录

事件

⬆ 返回目录

jQuery

⬆ 返回目录

ECMAScript 5 兼容性

⬆ 返回目录

ECMAScript 6 规范

  • 28.2 [modified][建议] 不要使用未到stage 3的 TC39提案

    为什么? 它们还不是终稿, 有可能被改动或废弃。我们使用的是Javascript, 但是提案暂时还不是Javascript。

About

✅ Waimai Business Platform javascript style guide(based on airbnb/javascript)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published