寫更漂亮的javascript

用更合理的方式寫 JavaScript

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

目錄

  1. 聲明變量
  2. 對象
  3. 數(shù)組
  4. 字符串
  5. 函數(shù)
  6. 箭頭函數(shù)
  7. 模塊
  8. 迭代器和生成器
  9. 屬性
  10. 變量
  11. 提升
  12. 比較運(yùn)算符和等號
  13. 代碼塊
  14. 注釋
  15. 空白
  16. 逗號
  17. 分號
  18. 類型轉(zhuǎn)換
  19. 命名規(guī)則

<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 分組

    為什么切省?當(dāng)你需要把已賦值變量賦值給未賦值變量時非常有用。

    // 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 是塊級作用域而不是函數(shù)作用域懒豹。

    // 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> 使用字面值創(chuàng)建對象芙盘。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> 創(chuàng)建有動態(tài)屬性名的對象時,使用可被計算的屬性名稱。

    為什么?因為這樣可以讓你在一個地方定義所有的對象屬性庸蔼。

    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> ==只==把對象中是無效標(biāo)識符的屬性用引號括起來雕沿。 eslint: quote-props

    為什么佳魔?通常認(rèn)為這樣寫更容易閱讀,更好的支持語法高亮晦炊,也更容易被許多 JS 引擎優(yōu)化鞠鲜。

    // 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> 不要直接調(diào)用 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> 使用對象字面量創(chuàng)建對象時稳衬,大括號必須換行霞捡。使用對象解構(gòu)賦值時,如果對象屬性超過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>
    單行定義對象時赊琳,最后一個成員不以逗號結(jié)尾。多行定義的對象砰碴,最后一個成員以逗號結(jié)尾躏筏。

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

數(shù)組 Arrays

  • 3.1 <a name='3.1'></a> 使用字面值創(chuàng)建數(shù)組。eslint: no-array-constructor

    // bad
    const items = new Array();
    
    // good
    const items = [];
    
  • 3.2 <a name='3.2'></a> 向數(shù)組添加元素時使用 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> 使用擴(kuò)展運(yùn)算符 ... 復(fù)制數(shù)組趁尼。

    // 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> 使用擴(kuò)展運(yùn)算符 ... 代替 Array.from 把一個類數(shù)組對象轉(zhuǎn)換成數(shù)組。

    const foo = document.querySelectorAll('.foo');
    
    // good
    const nodes = Array.from(foo);
    
    // best
    const nodes = [...foo];
    
  • 3.5 <a name='3.5'></a> 使用 Array.from 代替擴(kuò)展運(yùn)算符 ... 來映射迭代器猖辫,因為這樣可以避免創(chuàng)建一個中間數(shù)組酥泞。(array.from可以把類數(shù)組或者字符串轉(zhuǎn)化為數(shù)組)

    // bad
    const baz = [...foo].map(bar);
    
    // good
    const baz = Array.from(foo, bar);
    
  • 3.6 <a name='3.6'></a> 在數(shù)組方法的回調(diào)中使用return語句。如果函數(shù)只有一行代碼啃憎,并且只返回了一個表達(dá)式芝囤,那么可以省略返回值。關(guān)聯(lián) 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 如果數(shù)組有多行辛萍,請在打開和關(guān)閉數(shù)組括號前使用換行符悯姊。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 禁止使用稀疏數(shù)組。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== 個字節(jié)應(yīng)該使用字符串連接號換行挠轴。

  • 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> 不要在字符串中使用不必要的轉(zhuǎn)義字符。 eslint: no-useless-escape

    為什么纫谅?反斜杠導(dǎo)致代碼不可讀炫贤,因此應(yīng)該在必要的時候使用。

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

? 返回目錄

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

函數(shù) Functions

  • 5.1 <a name='5.1'></a> 使用函數(shù)表達(dá)式代替函數(shù)聲明(頂級函數(shù)不受限制)付秕。eslint: func-style

    為什么兰珍?函數(shù)聲明會把整個函數(shù)提升(hoisted),這導(dǎo)致在函數(shù)定義之前就可以引用該函數(shù)询吴。這會影響代碼的可讀性和可維護(hù)性掠河。

    // bad
    function foo() {
        // ...
    }
    
    // good
    const foo = function () {
        // ...
    };
    
    
  • 5.2 <a name='5.2'></a> 用括號包裹立即執(zhí)行函數(shù)表達(dá)式亮元。 eslint: wrap-iife

    為什么?立即執(zhí)行函數(shù)表達(dá)式是個單獨(dú)的模塊唠摹,用括號將函數(shù)和表示函數(shù)執(zhí)行的括號包裹起來爆捞,會使代碼更清晰。

    // 立即執(zhí)行函數(shù)表達(dá)式 (IIFE)
    (function () {
      console.log('Welcome to the Internet. Please follow me.');
    }());
    
  • 5.3 <a name='5.3'></a> 永遠(yuǎn)不要在一個非函數(shù)代碼塊(if跃闹、while 等)中聲明一個函數(shù)嵌削,應(yīng)該把函數(shù)賦給代碼塊外部的一個變量。瀏覽器允許你這么做望艺,但它們的解析表現(xiàn)不一致苛秕。eslint: no-loop-func
    注意: ECMA-262 把 block 定義為一組語句。函數(shù)聲明不是語句找默。閱讀 ECMA-262 關(guān)于這個問題的說明

  • //bad
    if (foo) {
        function test () {
            ...
        }
    //good
    let test;
    if(foo) {
        test = () => {
            ...
        }
    }
    
  • 5.4 <a name='6.4'></a> 永遠(yuǎn)不要把參數(shù)命名為 arguments艇劫。這將取代原來函數(shù)作用域內(nèi)的 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

    為什么风钻?使用 ... 能明確你要傳入的參數(shù)顷蟀。另外 rest 參數(shù)是一個真正的數(shù)組,而 arguments 是一個類數(shù)組骡技。

    // 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> 直接給函數(shù)的參數(shù)指定默認(rèn)值鸣个,不要使用一個變化的函數(shù)參數(shù)。

    // really bad
    const handleThings = function (opts) {
        // 不布朦!我們不應(yīng)該改變函數(shù)參數(shù)囤萤。
        // 更加糟糕: 如果參數(shù) opts 是 false 的話,它就會被設(shè)定為一個對象是趴。
        // 但這樣的寫法會造成一些 Bugs涛舍。
        //(譯注:例如當(dāng) opts 被賦值為空字符串,opts 仍然會被下一行代碼設(shè)定為一個空對象唆途。)
        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> 直接給函數(shù)參數(shù)賦值時需要避免副作用富雅。

    為什么?因為這樣的寫法讓人感到很困惑肛搬。

    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 不要使用構(gòu)造函數(shù)的方式創(chuàng)建一個新函數(shù)没佑。 eslint: no-new-func

    為什么?用構(gòu)造函數(shù)的方式創(chuàng)建函數(shù)類似于用 eval() 創(chuàng)建字符串滚婉,會有很多缺陷图筹。

    // 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 關(guān)鍵詞的空格。 eslint: space-before-function-paren space-before-blocks

    為什么?保持一致性远剩,這樣在添加和刪除函數(shù)時就不需要修改空格了扣溺。

    // 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 優(yōu)先使用擴(kuò)展運(yùn)算符 ... 來調(diào)用參數(shù)可變的函數(shù)。 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 有默認(rèn)值的參數(shù)總是放在最后一個痢掠。

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

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

  • 5.12 建議函數(shù)的圈復(fù)雜度(代碼的獨(dú)立現(xiàn)行路徑條數(shù))==在20以內(nèi)==驱犹。 eslint: complexity

為什么? 這樣可以減少函數(shù)的復(fù)雜度足画,使函數(shù)容易看懂雄驹。

? 返回目錄

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

箭頭函數(shù)

  • 6.1 <a name='6.1'></a> 當(dāng)你必須使用函數(shù)表達(dá)式(或傳遞一個匿名函數(shù))時,使用箭頭函數(shù)符號淹辞。eslint: prefer-arrow-callback, arrow-spacing

    為什么医舆?因為箭頭函數(shù)創(chuàng)造了新的一個 this 執(zhí)行環(huán)境(譯注:參考 Arrow functions - JavaScript | MDNES6 arrow functions, syntax and lexical scoping),通常情況下都能滿足你的需求象缀,而且這樣的寫法更為簡潔蔬将。

    為什么不?如果你有一個相當(dāng)復(fù)雜的函數(shù)央星,你或許可以把邏輯部分轉(zhuǎn)移到一個函數(shù)聲明上霞怀。

    // 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> 如果一個函數(shù)適合用一行寫出并且只有一個參數(shù),那就把花括號莉给、圓括號和 return 都省略掉毙石。如果不是,那就不要省略禁谦。eslint: arrow-parens, arrow-body-style

    為什么胁黑?語法糖废封。在鏈?zhǔn)秸{(diào)用中可讀性很高州泊。

    // 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 如果一個表達(dá)式跨行了,必須用括號括起來增強(qiáng)可讀性漂洋。

    為什么遥皂?這使得函數(shù)開始和結(jié)束的位置非常清晰。

    // 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 入?yún)⒈仨氂美ㄌ柪ㄆ饋砉羝slint: 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 避免混用箭頭函數(shù)的語法 (=>) 和比較運(yùn)算符 (<=, >=)贝咙。 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) 而不是其他非標(biāo)準(zhǔn)模塊系統(tǒng)样悟。你可以編譯為你喜歡的模塊系統(tǒng)。

    為什么?模塊化是未來趨勢窟她。

    // 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陈症。

    為什么?這樣能確保你只有一個默認(rèn) 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? 多個地方引入同一個文件會使代碼難以維護(hù)颁井。

    // 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厅贪。使用高階函數(shù)例如 map()reduce() 替代 for-offor-in。eslint: no-iterator no-restricted-syntax

    為什么雅宾?這加強(qiáng)了我們不變的規(guī)則卦溢。處理純函數(shù)的回調(diào)值更易讀,這比它帶來的副作用更重要秀又。

    使用 map()单寂、every()filter()吐辙、find()宣决、findIndex()reduce()昏苏、some()...來遍歷數(shù)組尊沸,使用 Object.keys()Object.values()贤惯、Object.entries() 生成數(shù)組以便遍歷對象洼专。

    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> 現(xiàn)在還不要使用 generators。

    為什么孵构?因為它們現(xiàn)在還沒法很好地編譯到 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> 當(dāng)通過變量訪問屬性時使用中括號 []颈墅。

    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 不要鏈?zhǔn)降慕o變量賦值蜡镶。eslint: no-multi-assign

    為什么?鏈?zhǔn)阶兞抠x值會創(chuàng)建隱式的全局變量恤筛。

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

    為什么?根據(jù) eslint 文檔毒坛,累加和累減會受到自動插入分號的影響望伦,并可能導(dǎo)致一些意外情況發(fā)生林说。

    // 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 避免使用魔法數(shù)字(白名單如下)。 eslint no-magic-numbers

    為什么屯伞?魔法數(shù)字讓人難難以明白開發(fā)者的意圖是什么述么,破壞代碼的可讀性和可維護(hù)性。

    // 以下為魔法數(shù)字白名單
    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 被賦予了一種稱為「暫時性死區(qū)(Temporal Dead Zones, TDZ)」的概念。這對于了解為什么 typeof 不再安全相當(dāng)重要饵撑。

    // 我們知道這樣運(yùn)行不了
    // (假設(shè) notDefined 不是全局變量)
    const example = function () {
        console.log(notDefined); // => throws a ReferenceError
    };
    
    // 由于變量提升的原因剑梳,
    // 在引用變量后再聲明變量是可以運(yùn)行的。
    // 注:變量的賦值 `true` 不會被提升滑潘。
    const example = function () {
        console.log(declaredButNotAssigned); // => undefined
        var declaredButNotAssigned = true;
    };
    
    // 編譯器會把函數(shù)聲明提升到作用域的頂層垢乙,
    // 這意味著我們的例子可以改寫成這樣:
    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> 匿名函數(shù)表達(dá)式的變量名會被提升,但函數(shù)內(nèi)容并不會语卤。

    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> 命名的函數(shù)表達(dá)式的變量名會被提升追逮,但函數(shù)名和函數(shù)內(nèi)容并不會。

    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> 函數(shù)聲明的名稱和函數(shù)體都會被提升粹舵。

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

? 返回目錄

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

比較運(yùn)算符和等號

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

  • 12.2 <a name='12.2'></a> 條件表達(dá)式例如 if 語句通過抽象方法 ToBoolean 強(qiáng)制計算它們的表達(dá)式并且總是遵守下面的規(guī)則:

    • 對象 被計算為 true
    • Undefined 被計算為 false
    • Null 被計算為 false
    • 布爾值 被計算為 布爾的值
    • 數(shù)字 如果是 +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> 布爾值使用簡寫漾唉,但是需要顯示比較字符串和數(shù)字。

    // 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.5 當(dāng) casedefault 包含的子句中有詞法聲明時,用大括號包裹场刑。(例如 let, const, function, and class). eslint: no-case-declarations

    為什么般此?詞法聲明在整個 switch 塊中是可見的,但只有在代碼執(zhí)行到 case 中變量被賦值時才會被初始化摇邦,當(dāng)多個 case 子句中定義相同的變量是時會出現(xiàn)問題恤煞。

    // 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 三元表達(dá)式不能嵌套使用屎勘。 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 避免出現(xiàn)不必要的三元表達(dá)式施籍。 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 當(dāng)混用操作符時,要用括號括起來概漱。唯一的例外是標(biāo)準(zhǔn)的算術(shù)運(yùn)算符 (+, -, *, & /)丑慎,因為它們很容易理解。 eslint: no-mixed-operators

    為什么?這提高了代碼的可讀性竿裂,并且使得開發(fā)者的意圖很清晰玉吁。

    // 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 代碼塊關(guān)閉括號的同一行进副。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 代碼塊中肯定會執(zhí)行 return 語句,那么后面的 else 就沒必要寫了悔常。如果在 else if 代碼塊中又有 if影斑,并且 if 代碼塊會執(zhí)行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 的前綴可以幫助其他開發(fā)者快速了解這是一個需要復(fù)查的問題残邀,或是給需要實現(xiàn)的功能提供一個解決方式皆辽。這將有別于常見的注釋,因為它們是可操作的芥挣。使用 FIXME -- need to figure this out 或者 TODO -- need to implement驱闷。

  • 14.3 <a name='14.3'></a> 使用 // FIXME: 標(biāo)注問題。

    class Calculator {
        constructor() {
    
            // FIXME: shouldn't use a global here
            total = 0;
        }
    }
    
  • 14.4 <a name='14.4'></a> 使用 // TODO: 標(biāo)注問題的解決方式空免。

    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 個空格作為縮進(jìn)遗嗽。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> 在控制語句(if鼓蜒、while 等)的小括號前放一個空格痹换。在函數(shù)調(diào)用及聲明中,不要在函數(shù)的參數(shù)列表前加空格都弹。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> 使用空格把運(yùn)算符隔開娇豫。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> 在使用長方法鏈時進(jìn)行縮進(jìn)畅厢。使用前面的點 . 強(qiáng)調(diào)這是方法調(diào)用而不是新語句冯痢。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==個字符以內(nèi)(包括空格)振劳。字符串、字符串模板和 URL 不受限制油狂。eslint: max-len

    為什么历恐?這么做保證了可讀性和可維護(hù)性寸癌。

    // 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> 增加結(jié)尾的逗號:需要弱贼。eslint: comma-dangle

    為什么? 這會讓 git diffs 更干凈蒸苇。另外,像 babel 這樣的轉(zhuǎn)譯器會移除結(jié)尾多余的逗號吮旅,也就是說你不必?fù)?dān)心老舊瀏覽器的尾逗號問題溪烤。

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

類型轉(zhuǎn)換

  • 18.1 <a name='18.1'></a> 在語句開始時執(zhí)行類型轉(zhuǎn)換庇勃。

  • 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> 對數(shù)字使用 parseInt 轉(zhuǎn)換氛什,并帶上類型轉(zhuǎn)換的基數(shù)。(不強(qiáng)制)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 導(dǎo)致我的程序變慢,
     * 改成使用位操作轉(zhuǎn)換數(shù)字快多了再层。
     */
    const val = inputValue >> 0;
    
  • 18.5 <a name='18.5'></a> 注: 小心使用位操作運(yùn)算符贸铜。數(shù)字會被當(dāng)成 64 位值,但是位操作運(yùn)算符總是返回 32 位的整數(shù)(參考)聂受。位操作處理大于 32 位的整數(shù)值時還會導(dǎo)致意料之外的行為蒿秦。關(guān)于這個問題的討論。最大的 32 位整數(shù)是 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>

命名規(guī)則

  • 19.1 <a name='19.1'></a> 避免單字母命名(e蛋济、i棍鳖、j、v碗旅、k渡处、t除外)。避免超長變量名(長度不超過60)祟辟。命名應(yīng)具備描述性和可讀性医瘫。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> 使用駝峰式命名對象旧困、函數(shù)和實例醇份。(對象的屬性不限制)eslint: camelcase

    // bad
    const OBJEcttsssss = {};
    const this_is_my_object = {};
    
    // good
    const thisIsMyObject = {};
    const thisIsMyFunction = function () {}
    
  • 19.3 <a name='19.3'></a> 使用帕斯卡式命名構(gòu)造函數(shù)或類。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 的引用吼具。使用箭頭函數(shù)或 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> 當(dāng)你導(dǎo)出默認(rèn)的函數(shù)時使用駝峰式命名怖竭。你的文件名必須和函數(shù)名完全保持一致。

    const makeStyleGuide = function () {
    }
    
    export default makeStyleGuide;
    
  • 19.7 <a name='19.7'></a> 當(dāng)你導(dǎo)出單例锣咒、函數(shù)庫侵状、空對象時使用帕斯卡式命名赞弥。

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

? 返回目錄

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末毅整,一起剝皮案震驚了整個濱河市趣兄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌悼嫉,老刑警劉巖艇潭,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異戏蔑,居然都是意外死亡蹋凝,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門总棵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鳍寂,“玉大人,你說我怎么就攤上這事情龄∑矗” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵骤视,是天一觀的道長鞍爱。 經(jīng)常有香客問我,道長专酗,這世上最難降的妖魔是什么睹逃? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮祷肯,結(jié)果婚禮上沉填,老公的妹妹穿的比我還像新娘。我一直安慰自己佑笋,他們只是感情好拜轨,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著允青,像睡著了一般橄碾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上颠锉,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天法牲,我揣著相機(jī)與錄音,去河邊找鬼琼掠。 笑死拒垃,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的瓷蛙。 我是一名探鬼主播悼瓮,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼戈毒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了横堡?” 一聲冷哼從身側(cè)響起埋市,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎命贴,沒想到半個月后道宅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡胸蛛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年污茵,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片葬项。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡泞当,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出民珍,到底是詐尸還是另有隱情襟士,我是刑警寧澤艘绍,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布筐骇,位于F島的核電站,受9級特大地震影響缺菌,放射性物質(zhì)發(fā)生泄漏津肛。R本人自食惡果不足惜章喉,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望身坐。 院中可真熱鬧秸脱,春花似錦、人聲如沸部蛇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涯鲁。三九已至巷查,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間抹腿,已是汗流浹背岛请。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留警绩,地道東北人崇败。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親后室。 傳聞我的和親對象是個殘疾皇子缩膝,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

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