寫更漂亮的javascript

用更合理的方式寫 JavaScript

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

目錄

  1. 聲明變量
  2. 對象
  3. 數(shù)組
  4. 字符串
  5. 函數(shù)
  6. 箭頭函數(shù)
  7. 模塊
  8. 迭代器和生成器
  9. 屬性
  10. 變量
  11. 提升
  12. 比較運算符和等號
  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 分組

    為什么?當你需要把已賦值變量賦值給未賦值變量時非常有用。

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

    為什么?通常認為這樣寫更容易閱讀,更好的支持語法高亮,也更容易被許多 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> 使用擴展運算符 ... 復(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> 使用擴展運算符 ... 代替 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 代替擴展運算符 ... 來映射迭代器,因為這樣可以避免創(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ù)只有一行代碼,并且只返回了一個表達式,那么可以省略返回值。關(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ù)表達式代替函數(shù)聲明(頂級函數(shù)不受限制)。eslint: func-style

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

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

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

    // 立即執(zhí)行函數(shù)表達式 (IIFE)
    (function () {
      console.log('Welcome to the Internet. Please follow me.');
    }());
    
  • 5.3 <a name='5.3'></a> 永遠不要在一個非函數(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> 永遠不要把參數(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ù)指定默認值,不要使用一個變化的函數(shù)參數(shù)。

    // really bad
    const handleThings = function (opts) {
        // 不!我們不應(yīng)該改變函數(shù)參數(shù)。
        // 更加糟糕: 如果參數(shù) opts 是 false 的話,它就會被設(shè)定為一個對象。
        // 但這樣的寫法會造成一些 Bugs。
        //(譯注:例如當 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)先使用擴展運算符 ... 來調(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 有默認值的參數(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ù)雜度(代碼的獨立現(xiàn)行路徑條數(shù))==在20以內(nèi)==。 eslint: complexity

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

? 返回目錄

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

箭頭函數(shù)

  • 6.1 <a name='6.1'></a> 當你必須使用函數(shù)表達式(或傳遞一個匿名函數(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),通常情況下都能滿足你的需求,而且這樣的寫法更為簡潔。

    為什么不?如果你有一個相當復(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

    為什么?語法糖。在鏈式調(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 如果一個表達式跨行了,必須用括號括起來增強可讀性。

    為什么?這使得函數(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ù)的語法 (=>) 和比較運算符 (<=, >=)。 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) 而不是其他非標準模塊系統(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。

    為什么?這樣能確保你只有一個默認 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。使用高階函數(shù)例如 map()reduce() 替代 for-offor-in。eslint: no-iterator no-restricted-syntax

    為什么?這加強了我們不變的規(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> 當通過變量訪問屬性時使用中括號 []。

    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

    為什么?鏈式變量賦值會創(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ā)者的意圖是什么,破壞代碼的可讀性和可維護性。

    // 以下為魔法數(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 不再安全相當重要。

    // 我們知道這樣運行不了
    // (假設(shè) notDefined 不是全局變量)
    const example = function () {
        console.log(notDefined); // => throws a ReferenceError
    };
    
    // 由于變量提升的原因,
    // 在引用變量后再聲明變量是可以運行的。
    // 注:變量的賦值 `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ù)表達式的變量名會被提升,但函數(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ù)表達式的變量名會被提升,但函數(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>

比較運算符和等號

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

  • 12.2 <a name='12.2'></a> 條件表達式例如 if 語句通過抽象方法 ToBoolean 強制計算它們的表達式并且總是遵守下面的規(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.5casedefault 包含的子句中有詞法聲明時,用大括號包裹。(例如 let, const, function, and class). eslint: no-case-declarations

    為什么?詞法聲明在整個 switch 塊中是可見的,但只有在代碼執(zhí)行到 case 中變量被賦值時才會被初始化,當多個 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 三元表達式不能嵌套使用。 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)不必要的三元表達式。 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 當混用操作符時,要用括號括起來。唯一的例外是標準的算術(shù)運算符 (+, -, *, & /),因為它們很容易理解。 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: 標注問題。

    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> 在控制語句(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> 使用空格把運算符隔開。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> 在使用長方法鏈時進行縮進。使用前面的點 . 強調(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

    為什么?這么做保證了可讀性和可維護性。

    // 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é)尾多余的逗號,也就是說你不必擔心老舊瀏覽器的尾逗號問題。

    // 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ù)。(不強制)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> 注: 小心使用位操作運算符。數(shù)字會被當成 64 位值,但是位操作運算符總是返回 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ǎo)出默認的函數(shù)時使用駝峰式命名。你的文件名必須和函數(shù)名完全保持一致。

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

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

? 返回目錄

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容