写更漂亮的javascript

用更合理的方式写 JavaScript

<a name="table-of-contents"></a>

目录

  1. 声明变量
  2. 对象
  3. 数组
  4. 字符串
  5. 函数
  6. 箭头函数
  7. 模块
  8. 迭代器和生成器
  9. 属性
  10. 变量
  11. 提升
  12. 比较运算符和等号
  13. 代码块
  14. 注释
  15. 空白
  16. 逗号
  17. 分号
  18. 类型转换
  19. 命名规则

<a name="types"></a>

声明变量

  • 1.1 <a name='1.1'></a> 使用let和const代替var

    • 不会变的声明用const
    //bad 
    var $cat = $('.cat')
    
    //good
    const $cat = $('.cat')
    
    
    • 会变动的声明用let
    //bad 
    var count = 1
    if (count<10) {
        count += 1
    }
    
    //good
    let count = 1
    if (count<10) {
        count += 1
    }
    
    
  • 1.2 <a name='1.2'></a> 将所有的 constlet 分组

    为什么?当你需要把已赋值变量赋值给未赋值变量时非常有用。

    // 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;
    
  • 1.3 <a name='1.3'></a> 在你需要的地方给变量赋值,但请把它们放在一个合理的位置。

    为什么?letconst 是块级作用域而不是函数作用域。

    // bad - unnecessary function call
    const checkName = function (hasName) {
        const name = getName();
    
        if (hasName === 'test') {
            return false;
        }
    
        if (name === 'test') {
            this.setName('');
            return false;
        }
    
        return name;
    };
    
    // good
    const checkName = function (hasName) {
        if (hasName === 'test') {
            return false;
        }
    
        const name = getName();
    
        if (name === 'test') {
            this.setName('');
            return false;
        }
    
        return name;
    };
    

⬆ 返回目录

<a name="objects"></a>

对象 Objects

  • 2.1 <a name='2.1'></a> 使用字面值创建对象。eslint: no-new-object

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

<a name="es6-computed-properties"></a>

  • 2.2 <a name='2.2'></a> 创建有动态属性名的对象时,使用可被计算的属性名称。

    为什么?因为这样可以让你在一个地方定义所有的对象属性。

    const getKey = function (k) {
        return `a key named ${k}`;
    };
    
    // bad
    const obj = {
        id: 1,
        name: 'San Francisco',
    };
    obj[getKey('enabled')] = true;
    
    // good
    const obj = {
        id: 1,
        name: 'San Francisco',
        [getKey('enabled')]: true,
    };
    

<a name="es6-object-shorthand"></a>

  • 2.3 <a name='2.3'></a> 使用对象方法的简写。eslint: object-shorthand

    // bad
    const atom = {
        value: 1,
    
        addValue: function (value) {
            return atom.value + value;
        },
    };
    
    // good
    const atom = {
        value: 1,
    
        addValue(value) {
            return atom.value + value;
        },
    };
    

<a name="es6-object-concise"></a>

  • 2.4 <a name='2.4'></a> 使用对象属性值的简写。eslint: object-shorthand

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

    const lukeSkywalker = 'Luke Skywalker';
    
    // bad
    const obj = {
        lukeSkywalker: lukeSkywalker,
    };
    
    // good
    const obj = {
        lukeSkywalker,
    };
    
  • 2.5 <a name='2.5'></a> 在对象属性声明前把简写的属性分组。

    为什么?因为这样能清楚地看出哪些属性使用了简写。

    const anakinSkywalker = 'Anakin Skywalker';
    const lukeSkywalker = 'Luke Skywalker';
    
    // bad
    const obj = {
        episodeOne: 1,
        twoJedisWalkIntoACantina: 2,
        lukeSkywalker,
        episodeThree: 3,
        mayTheFourth: 4,
        anakinSkywalker,
    };
    
    // good
    const obj = {
        lukeSkywalker,
        anakinSkywalker,
        episodeOne: 1,
        twoJedisWalkIntoACantina: 2,
        episodeThree: 3,
        mayTheFourth: 4,
    };
    
  • 2.6 <a name='2.6'></a> ==只==把对象中是无效标识符的属性用引号括起来。 eslint: quote-props

    为什么?通常认为这样写更容易阅读,更好的支持语法高亮,也更容易被许多 JS 引擎优化。

    // bad
    const bad = {
        'foo': 3,
        'bar': 4,
        'data-blah': 5,
    };
    
    // good
    const good = {
        foo: 3,
        bar: 4,
        'data-blah': 5,
    };
    
  • 2.7 <a name='2.7'></a> 不要直接调用 Object.prototype 方法,比如 hasOwnProperty, propertyIsEnumerable,和 isPrototypeOf

    为什么?这些方法有可能被对象本身的方法所遮蔽 - 比如{ hasOwnProperty: false } - 或者, 这个对象是个 null object (Object.create(null))。

    // bad
    console.log(object1.hasOwnProperty(key));
    
    // good
    console.log(Object.prototype.hasOwnProperty.call(object, key));
    
    // best
    const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
    /* or */
    import has from 'has'; // https://www.npmjs.com/package/has
    // ...
    console.log(has.call(object, key));
    
  • 2.8 <a name='2.8'></a> 使用对象字面量创建对象时,大括号必须换行。使用对象解构赋值时,如果对象属性超过2个,必须换行。eslint: object-curly-newline

    // bad
    const original = {a: 1, b: 2};
    const {height, largeSize, smallSize} = item;
    
    // good
    const original = {
        a: 1, 
        b: 2,
    };
    const {
        height,
        largeSize,
        smallSize,
    } = item;
    const {height, largeSize} = item;
    
  • 2.9 <a name='2.9'></a>
    单行定义对象时,最后一个成员不以逗号结尾。多行定义的对象,最后一个成员以逗号结尾。

    // bad
    const foo = { k1: v1, k2: v2, };
    const bar = {
        k1: v1,
        k2: v2
    };
    
    // good
    const foo = { k1: v1, k2: v2 };
    const bar = {
        k1: v1,
        k2: v2,
    };
    

⬆ 返回目录

<a name="arrays"></a>

数组 Arrays

  • 3.1 <a name='3.1'></a> 使用字面值创建数组。eslint: no-array-constructor

    // bad
    const items = new Array();
    
    // good
    const items = [];
    
  • 3.2 <a name='3.2'></a> 向数组添加元素时使用 Array#push 替代直接赋值。

    const someStack = [];
    
    
    // bad
    someStack[someStack.length] = 'abracadabra';
    
    // good
    someStack.push('abracadabra');
    

<a name="es6-array-spreads"></a>

  • 3.3 <a name='3.3'></a> 使用扩展运算符 ... 复制数组。

    // bad
    const len = items.length;
    const itemsCopy = [];
    let i;
    
    for (i = 0; i < len; i++) {
        itemsCopy[i] = items[i];
    }
    
    // good
    const itemsCopy = [...items];
    
  • 3.4 <a name='3.4'></a> 使用扩展运算符 ... 代替 Array.from 把一个类数组对象转换成数组。

    const foo = document.querySelectorAll('.foo');
    
    // good
    const nodes = Array.from(foo);
    
    // best
    const nodes = [...foo];
    
  • 3.5 <a name='3.5'></a> 使用 Array.from 代替扩展运算符 ... 来映射迭代器,因为这样可以避免创建一个中间数组。(array.from可以把类数组或者字符串转化为数组)

    // bad
    const baz = [...foo].map(bar);
    
    // good
    const baz = Array.from(foo, bar);
    
  • 3.6 <a name='3.6'></a> 在数组方法的回调中使用return语句。如果函数只有一行代码,并且只返回了一个表达式,那么可以省略返回值。关联 7.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 - no returned value means `memo` becomes undefined after the first iteration
    [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
        const flatten = memo.concat(item);
        memo[index] = flatten;
    });
    
    // good
    [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
        const flatten = memo.concat(item);
        memo[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;
    });
    
  • 3.7 如果数组有多行,请在打开和关闭数组括号前使用换行符。eslint: array-bracket-newline

    // bad
    const arr = [
        [0, 1], [2, 3], [4, 5],
    ];
    
    const objectInArray = [{
        id: 1,
    }, {
        id: 2,
    }];
    
    const numberInArray = [
        1, 2,
    ];
    
    // good
    const arr = [[0, 1], [2, 3], [4, 5]];
    
    const objectInArray = [
        {
            id: 1,
        },
        {
            id: 2,
        },
    ];
    
    const numberInArray = [
        1,
        2,
    ];
    
  • 3.8 禁止使用稀疏数组。eslint: no-sparse-arrays

    // bad
    const color = ['red',, 'blue'];
    
    // good
    const color = ['red', 'blue'];
    
    

⬆ 返回目录

<a name="strings"></a>

字符串 Strings

  • 4.1 <a name='4.1'></a> 字符串使用单引号 '' 。eslint: quotes

    // bad
    const name = "Capt. Janeway";
    
    // bad - template literals should contain interpolation or newlines
    const name = `Capt. Janeway`;
    
    // good
    const name = 'Capt. Janeway';
    
  • 4.2 <a name='4.2'></a> 字符串超过 ==80== 个字节应该使用字符串连接号换行。

  • 4.3 <a name='4.3'></a> 注:过度使用字串连接符号可能会对性能造成影响。jsPerf讨论。但是打包工具会在打包压缩后的代码中处理好字符串的拼接。而且字串连接符号对性能影响有限。

    // bad
    const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';
    
    // bad
    const errorMessage = 'This is a super long error that was thrown because \
    of Batman. When you stop to think about how Batman had anything to do \
    with this, you would get nowhere \
    fast.';
    
    // good
    const errorMessage = 'This is a super long error that was thrown because ' +
      'of Batman. When you stop to think about how Batman had anything to do ' +
      'with this, you would get nowhere fast.';
    

<a name="es6-template-literals"></a>

  • 4.4 <a name='4.4'></a> 程序化生成字符串时,使用模板字符串代替字符串连接。eslint: prefer-template template-curly-spacing

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

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

<a name="strings--eval"></a>

  • 4.5 <a name='4.5'></a>不要在字符串中使用 eval(),这个方法有要多缺陷。eslint: no-eval

<a name="strings--escaping"></a>

  • 4.6 <a name='4.6'></a> 不要在字符串中使用不必要的转义字符。 eslint: no-useless-escape

    为什么?反斜杠导致代码不可读,因此应该在必要的时候使用。

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

⬆ 返回目录

<a name="functions"></a>

函数 Functions

  • 5.1 <a name='5.1'></a> 使用函数表达式代替函数声明(顶级函数不受限制)。eslint: func-style

    为什么?函数声明会把整个函数提升(hoisted),这导致在函数定义之前就可以引用该函数。这会影响代码的可读性和可维护性。

    // bad
    function foo() {
        // ...
    }
    
    // good
    const foo = function () {
        // ...
    };
    
    
  • 5.2 <a name='5.2'></a> 用括号包裹立即执行函数表达式。 eslint: wrap-iife

    为什么?立即执行函数表达式是个单独的模块,用括号将函数和表示函数执行的括号包裹起来,会使代码更清晰。

    // 立即执行函数表达式 (IIFE)
    (function () {
      console.log('Welcome to the Internet. Please follow me.');
    }());
    
  • 5.3 <a name='5.3'></a> 永远不要在一个非函数代码块(ifwhile 等)中声明一个函数,应该把函数赋给代码块外部的一个变量。浏览器允许你这么做,但它们的解析表现不一致。eslint: no-loop-func
    注意: ECMA-262 把 block 定义为一组语句。函数声明不是语句。阅读 ECMA-262 关于这个问题的说明

  • //bad
    if (foo) {
        function test () {
            ...
        }
    //good
    let test;
    if(foo) {
        test = () => {
            ...
        }
    }
    
  • 5.4 <a name='6.4'></a> 永远不要把参数命名为 arguments。这将取代原来函数作用域内的 arguments 对象。

    // bad
    const nope = function (name, options, arguments) {
        // ...stuff...
    };
    
    // good
    const yup = function (name, options, args) {
        // ...stuff...
    };
    

<a name="es6-rest"></a>

  • 5.5 <a name='5.5'></a> 不要使用 arguments。可以选择 rest 语法 ... 替代。eslint: prefer-rest-params

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

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

<a name="es6-default-parameters"></a>

  • 5.6 <a name='5.6'></a> 直接给函数的参数指定默认值,不要使用一个变化的函数参数。

    // really bad
    const handleThings = function (opts) {
        // 不!我们不应该改变函数参数。
        // 更加糟糕: 如果参数 opts 是 false 的话,它就会被设定为一个对象。
        // 但这样的写法会造成一些 Bugs。
        //(译注:例如当 opts 被赋值为空字符串,opts 仍然会被下一行代码设定为一个空对象。)
        opts = opts || {};
        // ...
    };
    
    // still bad
    const handleThings = function (opts) {
        if (opts === void 0) {
            opts = {};
        }
        // ...
    };
    
    // good
    const handleThings = function (opts = {}) {
        // ...
    };
    
  • 5.7 <a name='5.7'></a> 直接给函数参数赋值时需要避免副作用。

    为什么?因为这样的写法让人感到很困惑。

    var b = 1;
    // bad
    const count = function (a = b++) {
        console.log(a);
    };
    count();  // 1
    count();  // 2
    count(3); // 3
    count();  // 3
    

<a name="functions--constructor"></a><a name="5.8"></a>

  • 5.8 不要使用构造函数的方式创建一个新函数。 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');
    

(所以是不使用class语法的意思吗)
<a name="functions--signature-spacing"></a><a name="5.9"></a>

  • 6.9 function 关键词的空格。 eslint: space-before-function-paren space-before-blocks

    为什么?保持一致性,这样在添加和删除函数时就不需要修改空格了。

    // bad
    const fetch = function(){};
    const get = function (){};
    const hold = function() {};
    
    // good
    const fetch = function () {};
    

<a name="functions--spread-vs-apply"></a><a name="5.10"></a>

  • 5.10 优先使用扩展运算符 ... 来调用参数可变的函数。 eslint: prefer-spread

    为什么? 这样写代码更干净,不必提供上下文。

    // 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]);
    
    

<a name="functions--defaults-last"></a><a name="5.11"></a>

  • 5.11 有默认值的参数总是放在最后一个。

    // bad
    const handleThings = function (opts = {}, name) {
        // ...
    };
    
    // good
    const handleThings = function (name, opts = {}) {
        // ...
    };
    ```  ```
    

<a name="functions--complexity"></a><a name="5.12"></a>

  • 5.12 建议函数的圈复杂度(代码的独立现行路径条数)==在20以内==。 eslint: complexity

为什么? 这样可以减少函数的复杂度,使函数容易看懂。

⬆ 返回目录

<a name="arrow-functions"></a>

箭头函数

  • 6.1 <a name='6.1'></a> 当你必须使用函数表达式(或传递一个匿名函数)时,使用箭头函数符号。eslint: prefer-arrow-callback, arrow-spacing

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

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

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

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

    // 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,
    }));
    
    // No implicit return with side effects
    const foo = function (callback) {
        const val = callback();
        if (val === true) {
            // Do something if callback returns true
        }
    };
    
    let bool = false;
    
    // bad
    foo(() => bool = true);
    
    // good
    foo(() => {
        bool = true;
    });
    

<a name="arrows--paren-wrap"></a><a name="6.3"></a>

  • 6.3 如果一个表达式跨行了,必须用括号括起来增强可读性。

    为什么?这使得函数开始和结束的位置非常清晰。

    // bad
    ['get', 'post', 'put'].map((httpMethod) => Object.prototype.hasOwnProperty.call(
            httpMagicObjectWithAVeryLongName,
            httpMethod,
        )
    );
    
    // good
    ['get', 'post', 'put'].map((httpMethod) => (
        Object.prototype.hasOwnProperty.call(
            httpMagicObjectWithAVeryLongName,
            httpMethod,
        )
    ));
    

<a name="arrows--one-arg-parens"></a><a name="6.4"></a>

  • 6.4 入参必须用括号括起来。eslint: arrow-parens

    为什么? 保持代码清晰和一致性。

    // bad
    [1, 2, 3].map(num => num * num);
    
    // good
    [1, 2, 3].map((num) => num * num);
    
    // bad
    [1, 2, 3].map(num => {
        const sum = num + 1;
        return num * sum;
    });
    
    // good
    [1, 2, 3].map((num) => {
        const sum = num + 1;
        return num * sum;
    });
    

<a name="arrows--confusing"></a><a name="6.5"></a>

  • 6.5 避免混用箭头函数的语法 (=>) 和比较运算符 (<=, >=)。 eslint: no-confusing-arrow

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

⬆ 返回目录

<a name="modules"></a>

模块 Modules

  • 7.1 <a name='7.1'></a> 总是使用模组 (import/export) 而不是其他非标准模块系统。你可以编译为你喜欢的模块系统。

    为什么?模块化是未来趋势。

    // 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;
    
  • 7.2 <a name='7.2'></a> 不要使用通配符 import。

    为什么?这样能确保你只有一个默认 export。

    // bad
    import * as AirbnbStyleGuide from './AirbnbStyleGuide';
    
    // good
    import AirbnbStyleGuide from './AirbnbStyleGuide';
    
  • 7.3 <a name='7.3'></a>不要从 import 中直接 export。

    为什么?虽然一行代码简洁明了,但让 import 和 export 各司其职让事情能保持一致。

    // bad
    // filename es6.js
    export {es6 as default} from './airbnbStyleGuide';
    
    // good
    // filename es6.js
    import {es6} from './AirbnbStyleGuide';
    export default es6;
    

<a name="modules--no-duplicate-imports"></a>

  • 7.4 不要多次 import 同一个文件。eslint: no-duplicate-imports

    Why? 多个地方引入同一个文件会使代码难以维护。

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

⬆ 返回目录

<a name="iterators-and-generators"></a>

Iterators and Generators

  • 8.1 <a name='8.1'></a> 不要使用 iterators。使用高阶函数例如 map()reduce() 替代 for-offor-in。eslint: no-iterator no-restricted-syntax

    为什么?这加强了我们不变的规则。处理纯函数的回调值更易读,这比它带来的副作用更重要。

    使用 map()every()filter()find()findIndex()reduce()some()...来遍历数组,使用 Object.keys()Object.values()Object.entries() 生成数组以便遍历对象。

    const numbers = [1, 2, 3, 4];
    
    // bad
    let sum = 0;
    for (let num of numbers) {
        sum += num;
    }
    
    sum === 10;
    
    // good
    let sum = 0;
    numbers.forEach((num) => {
        sum += num;
    });
    sum === 10;
    
    // best (use the functional force)
    const sum = numbers.reduce((total, num) => total + num, 0);
    sum === 10;
    
  • 8.2 <a name='8.2'></a> 现在还不要使用 generators。

    为什么?因为它们现在还没法很好地编译到 ES5。

⬆ 返回目录

<a name="properties"></a>

属性 Properties

  • 9.1 <a name='9.1'></a> 使用 . 来访问对象的属性。eslint: dot-notation

    const luke = {
        jedi: true,
        age: 12,
    };
    
    // bad
    const isJedi = luke['jedi'];
    
    // good
    const isJedi = luke.jedi;
    
  • 9.2 <a name='9.2'></a> 当通过变量访问属性时使用中括号 []

    const luke = {
        jedi: true,
        age: 12,
    };
    
    const getProp = (prop) => {
        return luke[prop];
    }
    
    const isJedi = getProp('jedi');
    

⬆ 返回目录

<a name="variables"></a>

变量 Variables

<a name="variables--no-chain-assignment"></a><a name="10.1"></a>

  • 11.1 不要链式的给变量赋值。eslint: no-multi-assign

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

    // 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 cat = dog = bird = 1;
    }());
    
    console.log(cat); // throws ReferenceError
    console.log(dog); // 1
    console.log(bird); // 1
    
    // good
    (function example() {
        let cat = 1;
        let dog = cat;
        let bird = cat;
    }());
    
    console.log(cat); // throws ReferenceError
    console.log(dogb); // throws ReferenceError
    console.log(bird); // throws ReferenceError
    
    // the same applies for `const`
    

<a name="variables--unary-increment-decrement"></a><a name="10.2"></a>

  • 10.2 避免使用累加和累减符号 (++, --)。 eslint no-plusplus

    为什么?根据 eslint 文档,累加和累减会受到自动插入分号的影响,并可能导致一些意外情况发生。

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

<a name="variables--no-magic-numbers"></a><a name="10.3"></a>

  • 10.3 避免使用魔法数字(白名单如下)。 eslint no-magic-numbers

    为什么?魔法数字让人难难以明白开发者的意图是什么,破坏代码的可读性和可维护性。

    // 以下为魔法数字白名单
    let magicNumberIgnore = [];
    
    // baisc number
    magicNumberIgnore = magicNumberIgnore.concat([
        -1, 0, 100, 1000, 10000
    ]);
    
    // datetime number
    magicNumberIgnore = magicNumberIgnore.concat([
        12, 24, 60, 3600
    ]);
    
    // httpcode number
    magicNumberIgnore = magicNumberIgnore.concat([
        200,
        301, 302, 303, 304,
        400, 401, 402, 403, 404,
        500, 501, 502, 503, 504
    ]);
    
    // bit number
    magicNumberIgnore = magicNumberIgnore.concat([
        1024
    ]);
    
    // number 1-49
    for (i = 1; i <= 49; i++) {
    
        if (magicNumberIgnore.indexOf(i) === -1) {
    
            magicNumberIgnore.push(i);
    
        }
    
    }
    
    // bad
    let soldNum = 102;
    let initNum = 80;
    
    // good
    const APPLE = 102;
    const STOCK = 80;
    let soldNum = APPLE;
    let initNum = STOCK;
    

⬆ 返回目录

<a name="hoisting"></a>

Hoisting

  • 11.1 <a name='11.1'></a> var 声明会被提升至该作用域的顶部,但它们赋值不会提升。letconst 被赋予了一种称为「暂时性死区(Temporal Dead Zones, TDZ)」的概念。这对于了解为什么 typeof 不再安全相当重要。

    // 我们知道这样运行不了
    // (假设 notDefined 不是全局变量)
    const example = function () {
        console.log(notDefined); // => throws a ReferenceError
    };
    
    // 由于变量提升的原因,
    // 在引用变量后再声明变量是可以运行的。
    // 注:变量的赋值 `true` 不会被提升。
    const example = function () {
        console.log(declaredButNotAssigned); // => undefined
        var declaredButNotAssigned = true;
    };
    
    // 编译器会把函数声明提升到作用域的顶层,
    // 这意味着我们的例子可以改写成这样:
    const example = function () {
        let declaredButNotAssigned;
        console.log(declaredButNotAssigned); // => undefined
        declaredButNotAssigned = true;
    };
    
    // 使用 const 和 let
    const example = function () {
        console.log(declaredButNotAssigned); // => throws a ReferenceError
        console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
        const declaredButNotAssigned = true;
    };
    
  • 11.2 <a name='11.2'></a> 匿名函数表达式的变量名会被提升,但函数内容并不会。

    const example = function () {
        console.log(anonymous); // => undefined
    
        anonymous(); // => TypeError anonymous is not a function
    
        var anonymous = function() {
            console.log('anonymous function expression');
        };
    };
    
  • 11.3 <a name='11.3'></a> 命名的函数表达式的变量名会被提升,但函数名和函数内容并不会。

    const example = function () {
        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.
    const example = function () {
        console.log(named); // => undefined
    
        named(); // => TypeError named is not a function
    
        var named = function named() {
            console.log('named');
        }
    };
    
  • 11.4 <a name='11.4'></a> 函数声明的名称和函数体都会被提升。

    const example = function () {
        superPower(); // => Flying
    
        function superPower() {
            console.log('Flying');
        }
    };
    
  • 想了解更多信息,参考 Ben CherryJavaScript Scoping & Hoisting

⬆ 返回目录

<a name="comparison-operators--equality"></a>

比较运算符和等号

  • 12.1 <a name='12.1'></a> 使用 ===!== 而不是 ==!=。eslint: eqeqeq

  • 12.2 <a name='12.2'></a> 条件表达式例如 if 语句通过抽象方法 ToBoolean 强制计算它们的表达式并且总是遵守下面的规则:

    • 对象 被计算为 true
    • Undefined 被计算为 false
    • Null 被计算为 false
    • 布尔值 被计算为 布尔的值
    • 数字 如果是 +0、-0、或 NaN 被计算为 false, 否则为 true
    • 字符串 如果是空字符串 '' 被计算为 false,否则为 true
    if ([0] && []) {
        // true
        // an array (even an empty one) is an object, objects will evaluate to true
    }
    
  • 12.3 <a name='12.3'></a> 布尔值使用简写,但是需要显示比较字符串和数字。

    // bad
    if (isValid === true) {
        // ...
    }
    
    // good
    if (isValid) {
        // ...
    }
    
    // bad
    if (name) {
        // ...
    }
    
    // good
    if (name !== '') {
        // ...
    }
    
    // bad
    if (collection.length) {
        // ...
    }
    
    // good
    if (collection.length > 0) {
        // ...
    }
    
  • 12.4 <a name='12.4'></a> 想了解更多信息,参考 Angus Croll 的 Truth Equality and JavaScript

<a name="comparison--switch-blocks"></a><a name="12.5"></a>

  • 12.5casedefault 包含的子句中有词法声明时,用大括号包裹。(例如 let, const, function, and class). eslint: no-case-declarations

    为什么?词法声明在整个 switch 块中是可见的,但只有在代码执行到 case 中变量被赋值时才会被初始化,当多个 case 子句中定义相同的变量是时会出现问题。

    // bad
    switch (foo) {
        case 1:
            let xx = 1;
            break;
        case 2:
            const yy = 2;
            break;
        case 3:
            const func = function () {
            // ...
            };
            break;
        default:
            get();
    }
    
    // good
    switch (foo) {
        case 1: {
            let xx = 1;
            break;
        }
        case 2: {
            const yy = 2;
            break;
        }
        case 3: {
            const func = function () {
            // ...
            };
            break;
        }
        case 4:
            bar();
            break;
        default: {
            get();
        }
    }
    

<a name="comparison--nested-ternaries"></a><a name="12.6"></a>

  • 12.6 三元表达式不能嵌套使用。 eslint: no-nested-ternary

    // bad
    const foo = maybe1 > maybe2
        ? "bar"
        : value1 > value2 ? "baz" : null;
    
    // split into 2 separated ternary expressions
    const maybeNull = value1 > value2 ? 'baz' : null;
    
    // better
    const foo = maybe1 > maybe2
        ? 'bar'
        : maybeNull;
    
    // best
    const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
    

<a name="comparison--unneeded-ternary"></a><a name="12.7"></a>

  • 12.7 避免出现不必要的三元表达式。 eslint: no-unneeded-ternary

    // bad
    const foo = maybe1 ? maybe1 : maybe2;
    const bar = correct ? true : false;
    const baz = wrong ? false : true;
    
    // good
    const foo = maybe1 || maybe2;
    const bar = !!correct;
    const baz = !wrong;
    

<a name="comparison--no-mixed-operators"></a>

  • 12.8 当混用操作符时,要用括号括起来。唯一的例外是标准的算术运算符 (+, -, *, & /),因为它们很容易理解。 eslint: no-mixed-operators

    为什么?这提高了代码的可读性,并且使得开发者的意图很清晰。

    // bad
    const foo = p1 && p2 < 0 || p3 > 0 || p4 + 1 === 0;
    
    // bad
    const bar = p1 ** p2 - 5 % p4;
    
    // bad
    // one may be confused into thinking (p1 || p2) && p3
    if (p1 || p2 && p3) {
        return p4;
    }
    
    // good
    const foo = (p1 && p2 < 0) || p3 > 0 || (p4 + 1 === 0);
    
    // good
    const bar = (p1 ** p2) - (5 % p4);
    
    // good
    if (p1 || (p2 && p3)) {
        return p4;
    }
    
    // good
    const bar = p1 + (p2 / p3 * p4);
    

⬆ 返回目录

<a name="blocks"></a>

代码块 Blocks

  • 13.1 <a name='13.1'></a> 使用大括号包裹所有的多行代码块。eslint: nonblock-statement-body-position

    // bad
    if (test)
        return false;
    
    // good
    if (test) {
        return false;
    }
    
    // good
    if (test) {
        return false;
    }
    
    // bad
    const func = function () {return false};
    
    // good
    const func = function () {
        return false;
    };
    
  • 13.2 <a name='13.2'></a> 如果通过 ifelse 使用多行代码块,把 else 放在 if 代码块关闭括号的同一行。eslint: brace-style

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

<a name="blocks--no-else-return"></a><a name="13.3"></a>

  • 13.3 如果 if 代码块中肯定会执行 return 语句,那么后面的 else 就没必要写了。如果在 else if 代码块中又有 if,并且 if 代码块会执行return 语句,那么可以分拆成多个 if 代码块。 eslint: no-else-return

    // bad
    const foo = function () {
        if (correct) {
            return correct;
        } else {
            return wrong;
        }
    };
    
    // bad
    const cats = function () {
        if (correct) {
            return correct;
        } else if (wrong) {
            return wrong;
        }
    };
    
    // bad
    const dogs = function () {
        if (correct) {
            return correct;
        } else {
            if (wrong) {
                return wrong;
            }
        }
    };
    
    // good
    const foo = function () {
        if (correct) {
            return correct;
        }
    
        return wrong;
    };
    
    // good
    const cats = function () {
        if (correct) {
            return correct;
        }
    
        if (wrong) {
            return wrong;
        }
        return false;
    };
    
    //good
    const dogs = function (correct) {
        if (correct) {
            if (confuse) {
                return wrong;
            }
        } else {
            return confuse;
        }
    };
    

⬆ 返回目录

<a name="comments"></a>

注释 Comments

  • 14.1 <a name='14.1'></a> 所有的注释开头都加一个空格,这样更利于阅读。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
     */
    const make = function (tag) {
    
        // ...
    
        return element;
    };
    
    // good
    /**
     * make() returns a new element
     * based on the passed-in tag name
     */
    const make = function (tag) {
    
        // ...
    
        return element;
    };
    
  • 14.2 <a name='14.2'></a> 给注释增加 FIXMETODO 的前缀可以帮助其他开发者快速了解这是一个需要复查的问题,或是给需要实现的功能提供一个解决方式。这将有别于常见的注释,因为它们是可操作的。使用 FIXME -- need to figure this out 或者 TODO -- need to implement

  • 14.3 <a name='14.3'></a> 使用 // FIXME: 标注问题。

    class Calculator {
        constructor() {
    
            // FIXME: shouldn't use a global here
            total = 0;
        }
    }
    
  • 14.4 <a name='14.4'></a> 使用 // TODO: 标注问题的解决方式。

    class Calculator {
        constructor() {
            
            // TODO: total should be configurable by an options param
            this.total = 0;
        }
    }
    

⬆ 返回目录

<a name="whitespace"></a>

空格 Whitespace

  • 15.1 <a name='15.1'></a> 使用 4 个空格作为缩进。eslint: indent

    // bad
    const func = function () {
    ∙∙const name = '';
    }
    
    // bad
    const func = function () {
    ∙const name = '';
    }
    
    // good
    const func = function () {
    ∙∙∙∙const name = '';
    }
    
  • 15.2 <a name='15.2'></a> 在大括号前放一个空格。eslint: space-before-blocks

    // bad
    const test = function (){
        console.log('test');
    }
    
    // good
    const test = function () {
        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',
    });
    
  • 15.3 <a name='15.3'></a> 在控制语句(ifwhile 等)的小括号前放一个空格。在函数调用及声明中,不要在函数的参数列表前加空格。eslint: keyword-spacing

    // bad
    if(isJedi) {
        fight ();
    }
    
    // good
    if (isJedi) {
        fight();
    }
    
    // bad
    const fight = function() {
        console.log ('Swooosh!');
    }
    
    // good
    const fight = function () {
        console.log('Swooosh!');
    }
    
  • 15.4 <a name='15.4'></a> 使用空格把运算符隔开。eslint: space-infix-ops

    // bad
    const i=j+5;
    
    // good
    const i = j + 5;
    
  • 15.5 <a name='15.5'></a> 在文件末尾插入一个空行。eslint: eol-last

    // bad
    import {es6} from './AirbnbStyleGuide';
        // ...
    export default es6;
    
    // bad
    import {es6} from './AirbnbStyleGuide';
        // ...
    export default es6;↵
    ↵
    
    // good
    import {es6} from './AirbnbStyleGuide';
        // ...
    export default es6;↵
    
  • 15.6 <a name='15.6'></a> 在使用长方法链时进行缩进。使用前面的点 . 强调这是方法调用而不是新语句。eslint: newline-per-chained-call no-whitespace-before-property

    // 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);
    
    // good
    const leds = stage.selectAll('.led').data(data);
    
  • 15.7 <a name='15.7'></a> 在块末和新语句前插入空行。

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

<a name="whitespace--padded-blocks"></a><a name="15.8"></a>

  • 15.8 不要在 block 代码块中加空行。 eslint: padded-blocks

    // bad
    const bar = function () {
    
        console.log(foo);
    
    };
    
    // bad
    if (baz) {
    
        console.log(qux);
    } else {
        console.log(foo);
    
    }
    
    // bad
    class Foo {
    
        constructor(bar) {
            this.bar = bar;
        }
    }
    
    // good
    const bar = function () {
        console.log(foo);
    };
    
    // good
    if (baz) {
        console.log(qux);
    } else {
        console.log(foo);
    }
    

<a name="whitespace--in-parens"></a><a name="15.9"></a>

  • 15.9 不要在小括号中加空格。 eslint: space-in-parens

    // bad
    const bar = function ( foo ) {
        return foo;
    };
    
    // good
    const bar = function (foo) {
        return foo;
    };
    
    // bad
    if ( foo ) {
        console.log(foo);
    }
    
    // good
    if (foo) {
        console.log(foo);
    }
    

<a name="whitespace--in-brackets"></a><a name="15.10"></a>

  • 15.10 不要在中括号中加空格。 eslint: array-bracket-spacing

    // bad
    const foo = [ 1, 2, 3 ];
    console.log(foo[ 0 ]);
    
    // good
    const foo = [1, 2, 3];
    console.log(foo[0]);
    

<a name="whitespace--in-braces"></a><a name="15.11"></a>

  • 15.11 不要在大括号中加空格。 eslint: object-curly-spacing

    // bad
    const foo = { clark: 'kent' };
    
    // good
    const foo = {clark: 'kent'};
    

<a name="whitespace--max-len"></a><a name="15.12"></a>

  • 15.12 尽量控制一行代码在==100==个字符以内(包括空格)。字符串、字符串模板和 URL 不受限制。eslint: max-len

    为什么?这么做保证了可读性和可维护性。

    // 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(() => {
            // do something...
        })
        .fail(() => {
            // do something...
        });
    

⬆ 返回目录

<a name="commas"></a>

逗号 Commas

  • 16.1 <a name='16.1'></a> 行首逗号:禁用。eslint: comma-style

    // 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',
    };
    
  • 16.2 <a name='16.2'></a> 增加结尾的逗号:需要。eslint: comma-dangle

    为什么? 这会让 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',
    ];
    
    // bad
    const createHero = function (
        firstName,
        lastName,
        inventorOf
    ) {
        // does nothing
    };
    
    // good
    const createHero = function (
        firstName,
        lastName,
        inventorOf,
    ) {
        // does nothing
    };
    
    // good (note that a comma must not appear after a "rest" element)
    const createHero = function (
        firstName,
        lastName,
        inventorOf,
        ...heroArgs
    ) {
        // does nothing
    };
    
    // bad
    createHero(
        firstName,
        lastName,
        inventorOf
    );
    
    // good
    createHero(
        firstName,
        lastName,
        inventorOf,
    );
    
    // good
    createHero(
        firstName,
        lastName,
        inventorOf,
        ...heroArgs
    );
    

⬆ 返回目录

<a name="semicolons"></a>

分号 Semicolons

  • 17.1 <a name='17.1'></a> 使用分号。eslint: semi

    Why? When JavaScript encounters a line break without a semicolon, it uses a set of rules called Automatic Semicolon Insertion to determine whether or not it should regard that line break as the end of a statement, and (as the name implies) place a semicolon into your code before the line break if it thinks so. ASI contains a few eccentric behaviors, though, and your code will break if JavaScript misinterprets your line break. These rules will become more complicated as new features become a part of JavaScript. Explicitly terminating your statements and configuring your linter to catch missing semicolons will help prevent you from encountering issues.

    // bad - raises exception
    const luke = {}
    const leia = {}
    [luke, leia].forEach(jedi => jedi.father = 'vader')
    
    // bad - raises exception
    const reaction = "No! That's impossible!"
    (async function meanwhileOnTheFalcon(){
        // handle `leia`, `lando`, `chewie`, `r2`, `c3p0`
        // ...
    }())
    
    // bad - returns `undefined` instead of the value on the next line - always happens when `return` is on a line by itself because of ASI!
    const foo = foo() {
        return
            'search your feelings, you know it to be foo'
    };
    
    // good
    const luke = {};
    const leia = {};
    [luke, leia].forEach((jedi) => {
        jedi.father = 'vader';
    });
    
    // good
    const reaction = "No! That's impossible!";
    (async function meanwhileOnTheFalcon(){
        // handle `leia`, `lando`, `chewie`, `r2`, `c3p0`
        // ...
    }());
    
    // good
    const foo = foo() {
        return 'search your feelings, you know it to be foo';
    };
    

    Read more.

⬆ 返回目录

<a name="type-casting--coercion"></a>

类型转换

  • 18.1 <a name='18.1'></a> 在语句开始时执行类型转换。

  • 18.2 <a name='18.2'></a> 字符串:eslint: no-new-wrappers

    // => this.reviewScore = 9;
    
    // bad
    const totalScore = new String(this.reviewScore); // typeof totalScore is "object" not "string"
    
    // bad
    const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf()
    
    // bad
    const totalScore = this.reviewScore.toString(); // isn’t guaranteed to return a string
    
    // good
    const totalScore = String(this.reviewScore);
    
  • 18.3 <a name='18.3'></a> 对数字使用 parseInt 转换,并带上类型转换的基数。(不强制)eslint: radix no-new-wrappers

    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);
    
  • 18.4 <a name='18.4'></a> 如果因为某些原因 parseInt 成为你所做的事的瓶颈而需要使用位操作解决性能问题时,留个注释说清楚原因和你的目的。

    // good
    /**
     * 使用 parseInt 导致我的程序变慢,
     * 改成使用位操作转换数字快多了。
     */
    const val = inputValue >> 0;
    
  • 18.5 <a name='18.5'></a> 注: 小心使用位操作运算符。数字会被当成 64 位值,但是位操作运算符总是返回 32 位的整数(参考)。位操作处理大于 32 位的整数值时还会导致意料之外的行为。关于这个问题的讨论。最大的 32 位整数是 2,147,483,647:

    2147483647 >> 0 //=> 2147483647
    2147483648 >> 0 //=> -2147483648
    2147483649 >> 0 //=> -2147483647
    
  • 18.6 <a name='18.6'></a> 布尔:eslint: no-new-wrappers

    const age = 0;
    
    // bad
    const hasAge = new Boolean(age);
    
    // good
    const hasAge = Boolean(age);
    
    // good
    const hasAge = !!age;
    

⬆ 返回目录

<a name="naming-conventions"></a>

命名规则

  • 19.1 <a name='19.1'></a> 避免单字母命名(e、i、j、v、k、t除外)。避免超长变量名(长度不超过60)。命名应具备描述性和可读性。eslint: id-length

    // bad
    const q = function () {
        // ...stuff...
    };
    
    // bad
    const getWebBeibei11MaylikeRecommendPageSize20Page1XidMTcxNTM2Njcxsa = function () {
        // ...stuff...
    };
    
    // good
    const query = function () {
        // ...stuff..。
    };
    
  • 19.2 <a name='19.2'></a> 使用驼峰式命名对象、函数和实例。(对象的属性不限制)eslint: camelcase

    // bad
    const OBJEcttsssss = {};
    const this_is_my_object = {};
    
    // good
    const thisIsMyObject = {};
    const thisIsMyFunction = function () {}
    
  • 19.3 <a name='19.3'></a> 使用帕斯卡式命名构造函数或类。eslint: new-cap

    // 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',
    });
    
  • 19.4 <a name='19.4'></a> 别保存 this 的引用。使用箭头函数或 Function#bind。

    // bad
    const foo = function () {
        const self = this;
        return function() {
            console.log(self);
        };
    };
    
    // bad
    const foo = function () {
        const that = this;
        return function() {
            console.log(that);
        };
    };
    
    // good
    const foo = function () {
        return () => {
            console.log(this);
        };
    };
    
  • 19.5 <a name='19.5'></a> 如果你的文件只输出一个类,那你的文件名必须和类名完全保持一致。

    // file contents
    class CheckBox {
        // ...
    }
    export default CheckBox;
    
    // in some other file
    // bad
    import CheckBox from './checkBox';
    
    // bad
    import CheckBox from './check_box';
    
    // good
    import CheckBox from './CheckBox';
    
  • 19.6 <a name='19.6'></a> 当你导出默认的函数时使用驼峰式命名。你的文件名必须和函数名完全保持一致。

    const makeStyleGuide = function () {
    }
    
    export default makeStyleGuide;
    
  • 19.7 <a name='19.7'></a> 当你导出单例、函数库、空对象时使用帕斯卡式命名。

    const AirbnbStyleGuide = {
        es6: {
        }
    };
    
    export default AirbnbStyleGuide;
    

⬆ 返回目录

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容