Skip to content

naremloa/javascript

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 

Repository files navigation

Airbnb JavaScript Style Guide() {

一份彙整了在 JavasScript 中被普遍使用的風格指南。

Downloads Gitter

其他風格指南

翻譯自 Airbnb JavaScript Style Guide

目錄

  1. 資料型態
  2. 參考
  3. 物件
  4. 陣列
  5. 解構子
  6. 字串
  7. 函式
  8. 箭頭函式
  9. 建構子
  10. 模組
  11. 迭代器及產生器
  12. 屬性
  13. 變數
  14. 提升
  15. 條件式與等號
  16. 區塊
  17. 控制敘述
  18. 註解
  19. 空格
  20. 逗號
  21. 分號
  22. 型別轉換
  23. 命名規則
  24. 存取器
  25. 事件
  26. jQuery
  27. ECMAScript 5 相容性
  28. ECMAScript 6 風格
  29. 標準函示庫
  30. 測試
  31. 效能
  32. 資源
  33. 誰在使用
  34. 翻譯
  35. JavaScript 風格指南
  36. 和我們討論 Javascript
  37. 貢獻者
  38. 授權許可
  39. 修訂
  40. 部分詞彙翻譯對照

資料型態(Types)

  • 1.1 基本:你可以直接存取基本資料型態。

    • 字串(string)
    • 數字(number)
    • 布林(boolean)
    • null
    • undefined
    • 符號(symbol)
    const foo = 1;
    let bar = foo;
    
    bar = 9;
    
    console.log(foo, bar); // => 1, 9
    • 不建議在目標瀏覽器/環境不支持es6的情況下使用符號(symbol)。現階段不能通過polyfill的方式使符號受到原生的支持。
  • 1.2 複合:你需要透過引用的方式存取複合資料型態。

    • 物件
    • 陣列
    • 函式
    const foo = [1, 2];
    const bar = foo;
    
    bar[0] = 9;
    
    console.log(foo[0], bar[0]); // => 9, 9

⬆ 回到頂端

參考(References)

  • 2.1 對於所有的參考使用 const;避免使用 var。eslint: prefer-const, no-const-assign

    為什麼?因為這能確保你無法對參考重新賦值(reassign),得以不讓你的程式碼有錯誤或難以理解。

    // bad
    var a = 1;
    var b = 2;
    
    // good
    const a = 1;
    const b = 2;
  • 2.2 如果你需要可變動的參考,使用 let 代替 var。eslint: no-var

    為什麼?因為 let 的作用域是在區塊內,而不像 var 是在函式內。

    // bad
    var count = 1;
    if (true) {
      count += 1;
    }
    
    // good, use the let.
    let count = 1;
    if (true) {
      count += 1;
    }
  • 2.3 請注意,letconst 的作用域都只在區塊內。

    // const 及 let 只存在於他們被定義的區塊內。
    {
      let a = 1;
      const b = 1;
    }
    console.log(a); // ReferenceError
    console.log(b); // ReferenceError

⬆ 回到頂端

物件

  • 3.2 建立具有動態屬性名稱的物件時請使用可被計算的屬性名稱。

    為什麼?因為這樣能夠讓你在同一個地方定義一個物件所有的物件屬性。

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

  • 3.3 使用物件方法的簡寫。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;
      },
    };

  • 3.4 使用屬性值的簡寫。eslint: object-shorthand

    為什麼?因為寫起來更短且更有描述性。

    const lukeSkywalker = 'Luke Skywalker';
    
    // bad
    const obj = {
      lukeSkywalker: lukeSkywalker,
    };
    
    // good
    const obj = {
      lukeSkywalker,
    };
  • 3.5 將簡寫的屬性分成一組,放在物件宣告的開頭部分。

    為什麼?因為這樣能夠很容易的看出哪些屬性使用了簡寫。

    const anakinSkywalker = 'Anakin Skywalker';
    const lukeSkywalker = 'Luke Skywalker';
    
    // bad
    const obj = {
      episodeOne: 1,
      twoJediWalkIntoACantina: 2,
      lukeSkywalker,
      episodeThree: 3,
      mayTheFourth: 4,
      anakinSkywalker,
    };
    
    // good
    const obj = {
      lukeSkywalker,
      anakinSkywalker,
      episodeOne: 1,
      twoJediWalkIntoACantina: 2,
      episodeThree: 3,
      mayTheFourth: 4,
    };
  • 3.6 只在無效的屬性加上引號。eslint: quote-props

    為什麼?整體來說,我們認為這在主觀上更容易閱讀。它會改善語法高亮,也能讓多數的 JS 引擎更容易最優化。

    // bad
    const bad = {
      'foo': 3,
      'bar': 4,
      'data-blah': 5,
    };
    
    // good
    const good = {
      foo: 3,
      bar: 4,
      'data-blah': 5,
    };
  • *3.7 不要直接使用 Object.prototype 下的方法,如 hasOwnPropertypropertyIsEnumerableisPrototypeOf。(todo)

    為什麼?考慮如下情況: { hasOwnProperty: false } 或是一個為null的物件(Object.create(null))。在這些情況下,這些方法都不會正常的執行。

    //bad
    console.log(object.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));
  • 3.8 相比 Object.assign 更推薦用物件的擴展運算子(spread operator)來對物件進行淺拷貝(shallow-copy)。使用物件的剩餘運算子(rest operator)省略確切的屬性名來獲取新的物件。

    // very bad
    const original = { a: 1, b: 2 };
    const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ
    delete copy.a; //so does this
    
    //bad
    const original = { a: 1, b: 2 };
    const copy = Object.assign({}, original, { c: 3 }); //copy => { a: 1, b: 2, c: 3 }
    
    //good
    const original = { a: 1, b: 2 };
    const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
    
    const { a, ...noA } = copy; // noA => { b: 2, c: 3 }

⬆ 回到頂端

陣列

  • 4.1 使用字面值語法(literal syntax)建立陣列。eslint: no-array-constructor

    // bad
    const items = new Array();
    
    // good
    const items = [];
  • 4.2 要向陣列增加元素時,使用Array#push來取代直接操作陣列

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

  • 4.3 使用陣列的擴展運算子 ... 來複製陣列。

    // bad
    const len = items.length;
    const itemsCopy = [];
    let i;
    
    for (i = 0; i < len; i++) {
      itemsCopy[i] = items[i];
    }
    
    // good
    const itemsCopy = [...items];
  • 4.4 如果要轉換一個類陣列物件至陣列,可以使用擴展運算子 ... 來取代 Array.from

    const foo = document.querySelectorAll('.foo');
    
    // good
    const nodes = Array.from(foo);
    
    // best
    const nodes = [...foo];
  • 4.5 如果需要用回呼函式來處理整個迭代器(mapping over iterables),使用 Array.from 來取代擴展運算子 ...。因為它能夠避免再多弄出一個中間陣列。

    // bad
    const baz = [...foo].map(bar);
    
    // good
    const baz = Array.from(foo, bar);
  • 4.6 在用陣列的方法時方法要有回傳值(方法裡要有 return 宣告)。若函式本體是如 8.2 的單一語法,那麼省略 return 是可以的(箭頭函式在某些情況,解釋器能幫你自動補上 return )。eslint: array-callback-return

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

⬆ 回到頂端

解構子

  • 5.1 存取或使用有多個屬性的物件時,請使用物件解構子。eslint: prefer-destructuring

    為什麼?因為解構子能夠節省你對這些屬性建立暫時的參考。

    // bad
    function getFullName(user) {
      const firstName = user.firstName;
      const lastName = user.lastName;
    
      return `${firstName} ${lastName}`;
    }
    
    // good
    function getFullName(user) {
      const { firstName, lastName } = user;
      return `${firstName} ${lastName}`;
    }
    
    // best
    function getFullName({ firstName, lastName }) {
      return `${firstName} ${lastName}`;
    }
  • 5.2 使用陣列解構子。eslint: prefer-destructuring

    const arr = [1, 2, 3, 4];
    
    // bad
    const first = arr[0];
    const second = arr[1];
    
    // good
    const [first, second] = arr;
  • 5.3 需要回傳多個值時請使用物件解構子,而不是陣列解構子。

    為什麼?因為你可以增加新的屬性或改變排序且不須更動呼叫的位置。

    // bad
    function processInput(input) {
      // 這時神奇的事情出現了
      return [left, right, top, bottom];
    }
    
    // 呼叫時必須考慮回傳資料的順序。
    const [left, __, top] = processInput(input);
    
    // good
    function processInput(input) {
      // 這時神奇的事情出現了
      return { left, right, top, bottom };
    }
    
    // 呼叫時只需選擇需要的資料
    const { left, right } = processInput(input);

⬆ 回到頂端

字串

  • 6.1 字串請使用單引號 ''。eslint: quotes

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

  • 6.2 如果字串超過 100 個字元,請使用字串連接符號換行。

    為什麼?處理割裂開的字串讓人很痛苦,而且會降低程式的可搜索性

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

  • 6.3 當以程式方式建構字串時,請使用模板字串而不是連接字串。eslint: prefer-template template-curly-spacing

    為什麼?因為模板字串更具有可讀性,正確的換行符號及字串插值功能讓語法更簡潔。

    // bad
    function sayHi(name) {
      return 'How are you, ' + name + '?';
    }
    
    // bad
    function sayHi(name) {
      return ['How are you, ', name, '?'].join();
    }
    
    // bad
    function sayHi(name) {
      return `How are you, ${ name }?`;
    }
    
    // good
    function sayHi(name) {
      return `How are you, ${name}?`;
    }
  • 6.4 千萬不要在字串中使用 eval(),會帶來許多不安全因素。eslint: no-eval

  • 6.5 在字串中避免使用無意義的跳脫字元。eslint: no-useless-escape

    為什麼? 反斜線會損害可讀性,所以它應該只出現在需要的地方。

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

⬆ 回到頂端

函式

  • 7.1 使用命名的函式陳述式,取代函式運算式。

    為什麼?Function declarations are hoisted, which means that it’s easy - too easy - to reference the function before it is defined in the file. This harms readability and maintainability. If you find that a function’s definition is large or complex enough that it is interfering with understanding the rest of the file, then perhaps it’s time to extract it to its own module! Don’t forget to explicitly name the expression, regardless of whether or not the name is inferred from the containing variable (which is often the case in modern browsers or when using compilers such as Babel). This eliminates any assumptions made about the Error's call stack. (Discussion)

    // bad
    function foo() {
      // ...
    }
    
    // bad
    const foo = function () {
      // ...
    };
    
    // good
    // lexical name distinguished from the variable-referenced invocation(s)
    const short = function longUniqueMoreDescriptiveLexicalFoo() {
      // ...
    };
  • 7.2 立即函式就是立即函式,不要使用函式陳述式。eslint: wrap-iife jscs: requireParenthesesAroundIIFE

    為什麼?一個立即函式是個獨立的單元-將函式及呼叫函式的括號包起來明確表示這一點。注意在模組世界的任何地方,你都不需要使用立即函式。

    // 立即函式(IIFE)
    (function () {
      console.log('Welcome to the Internet. Please follow me.');
    }());
  • 7.3 絕對不要在非函式的區塊(if、while 等等)宣告函式。你可以將函式賦予至變數解決這個問題。瀏覽器會允許你這麼做,但不同瀏覽器產生的結果可能會不同。eslint: no-loop-func

  • 7.4 **注意:**ECMA-262 將區塊定義為陳述式。函式宣告則不是陳述式。閱讀 ECMA-262 關於這個問題的說明

    // bad
    if (currentUser) {
      function test() {
        console.log('Nope.');
      }
    }
    
    // good
    let test;
    if (currentUser) {
      test = () => {
        console.log('Yup.');
      };
    }
  • 7.5 請勿將參數命名為 arguments,這樣會將覆蓋掉函式作用域傳來的 arguments

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

  • 7.6 絕對不要使用 arguments,可以選擇使用 rest 語法 ... 替代。prefer-rest-params

    為什麼?使用 ... 能夠明確指出你要將參數傳入哪個變數。再加上 rest 參數是一個真正的陣列,而不像 arguments 似陣列而非陣列。

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

  • 7.7 使用預設參數的語法,而不是變動函式的參數。

    // really bad
    function handleThings(opts) {
      // 不!我們不該變動函式的參數。
      // Double bad: 如果 opt 是 false ,那們它就會被設定為一個物件,
      // 或許你想要這麼做,但是這樣可能會造成一些 Bug。
      opts = opts || {};
      // ...
    }
    
    // still bad
    function handleThings(opts) {
      if (opts === void 0) {
        opts = {};
      }
      // ...
    }
    
    // good
    function handleThings(opts = {}) {
      // ...
    }
  • 7.8 使用預設參數時請避免副作用。

    為什麼?因為這樣會讓思緒混淆。

    var b = 1;
    // bad
    function count(a = b++) {
      console.log(a);
    }
    count();  // 1
    count();  // 2
    count(3); // 3
    count();  // 3
  • 7.9 永遠將預設參數放置於最後。

    // bad
    function handleThings(opts = {}, name) {
      // ...
    }
    
    // good
    function handleThings(name, opts = {}) {
      // ...
    }
  • 7.10 千萬別使用建構函式去建立一個新的函式。eslint: no-new-func

    為什麼?透過這種方式建立一個函數來計算字串類似於 eval(),會造成許多的漏洞。

    // bad
    var add = new Function('a', 'b', 'return a + b');
    
    // still bad
    var subtract = Function('a', 'b', 'return a - b');
  • 7.11 在函式的標示後放置空格。eslint: space-before-function-parenspace-before-blocks

    為什麼?一致性較好,而且你不應該在新增或刪除名稱時增加或減少空格。

    // bad
    const f = function(){};
    const g = function (){};
    const h = function() {};
    
    // good
    const x = function () {};
    const y = function a() {};
  • 7.12 切勿變更參數。eslint: no-param-reassign

    為什麼?操作作為參數傳入的物件可能導致變數產生原呼叫者不期望的副作用。

    // bad
    function f1(obj) {
      obj.key = 1;
    };
    
    // good
    function f2(obj) {
      const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
    };
  • 7.13 切勿重新賦值給參數。eslint: no-param-reassign

    為什麼?將參數重新賦值可能導致意外的行為,尤其在存取 arguments 物件時。它可能會引起最佳化的問題,尤其在 V8。

    // bad
    function f1(a) {
      a = 1;
    }
    
    function f2(a) {
      if (!a) { a = 1; }
    }
    
    // good
    function f3(a) {
      const b = a || 1;
    }
    
    function f4(a = 1) {
    }
  • 7.14 推薦用擴展運算子(spread operator) ... 呼叫可變參數函式(variadic functions)。eslint: prefer-spread

    為什麼?它很簡潔,你不需要再多加其他內容。you can not easily compose new with apply.

    // 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]);
  • [7.15(#7.15)] 函式有個參數或是呼叫時,應該讓每一個都獨立一行存在,並在最後一個的末尾處也帶上逗號。eslint: function-paren-newline

    // bad
    function foo(bar,
                baz,
                quux) {
      // ...
    }
    
    // good
    function foo(
      bar,
      baz,
      quux,
    ) {
      // ...
    }
    
    // bad
    console.log(foo,
      bar,
      baz);
    
    // good
    console.log(
      foo,
      bar,
      baz,
    );

⬆ 回到頂端

箭頭函式

  • 8.1 當你必須使用函式表達式(或傳遞一個匿名函式)時,請使用箭頭函式的符號。eslint: prefer-arrow-callback, arrow-spacing

    為什麼?它會在有 this 的內部建立了一個新版本的函式,通常功能都是你所想像的,而且語法更為簡潔。

    為什麼不?如果你已經有一個相當複雜的函式時,或許你該將邏輯都移到一個函式宣告上。

    // bad
    [1, 2, 3].map(function (x) {
      const y = x + 1;
      return x * y;
    });
    
    // good
    [1, 2, 3].map((x) => {
      const y = x + 1;
      return x * y;
    });
  • 8.2 如果函式內容只有單一敘述,且返回一個沒有副作用的陳述式,你可以很隨性的省略大括號及隱藏回傳。否則請保留大括號並使用 return 語法。eslint: arrow-parens, arrow-body-style

    為什麼?因為這是語法糖。這樣能夠在多個函式鏈結在一起的時候更易讀。

    // 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
    function foo(callback) {
      const val = callback();
      if (val === true) {
        // Do something if callback returns true
      }
    }
    
    let bool = false;
    
    // bad
    foo(() => bool = true);
    
    // good
    foo(() => {
      bool = true;
    });
  • 8.3 如果表達式跨了多行,請將它們包在括號中增加可讀性。

    為什麼?這麼做更清楚的表達函式的開始與結束的位置。

    // bad
    ['get', 'post', 'put'].map(httpMethod => Object.prototype.hasOwnProperty.call(
        httpMagicObjectWithAVeryLongName,
        httpMethod,
      )
    );
    
    // good
    ['get', 'post', 'put'].map(httpMethod => (
      Object.prototype.hasOwnProperty.call(
        httpMagicObjectWithAVeryLongName,
        httpMethod,
      )
    ));
  • 8.4 如果你的函式只使用一個參數,那麼可以很隨意的省略括號。否則請在參數兩側加上括號。當然,也可以總是在參數兩側加上括號。讓兩側總是有括號的eslint設置如後所示。eslint: arrow-parens

    為什麼?減少視覺上的混亂。

    // bad
    [1, 2, 3].map((x) => x * x);
    
    // good
    [1, 2, 3].map(x => x * x);
    
    // good
    [1, 2, 3].map(number => (
      `A long string with the ${number}. It’s so long that we’ve broken it ` +
      'over multiple lines!'
    ));
    
    // bad
    [1, 2, 3].map(x => {
      const y = x + 1;
      return x * y;
    });
    
    // good
    [1, 2, 3].map((x) => {
      const y = x + 1;
      return x * y;
    });
  • 8.5 避免混淆箭頭函式語法(=>)及比較運算子(<=>=)。eslint: no-confusing-arrow

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

  • 8.6 當箭頭函式隱式調用return時,函式體需要用括號包起來。eslint: implicit-arrow-linebreak

    // bad
    (foo) =>
      bar;
    (foo) =>
      (bar);
    
    // good
    (foo) => bar;
    (foo) => (bar);
    (foo) => (
       bar
    )

⬆ 回到頂端

建構子

  • 9.1 總是使用 class。避免直接操作 prototype

    為什麼?因為 class 語法更簡潔且更易讀。

    // bad
    function Queue(contents = []) {
      this._queue = [...contents];
    }
    Queue.prototype.pop = function () {
      const value = this._queue[0];
      this._queue.splice(0, 1);
      return value;
    }
    
    
    // good
    class Queue {
      constructor(contents = []) {
        this._queue = [...contents];
      }
      pop() {
        const value = this._queue[0];
        this._queue.splice(0, 1);
        return value;
      }
    }
  • 9.2 使用 extends 繼承。

    為什麼?因為他是一個內建繼承原型方法的方式,且不會破壞 instanceof

    // bad
    const inherits = require('inherits');
    function PeekableQueue(contents) {
      Queue.apply(this, contents);
    }
    inherits(PeekableQueue, Queue);
    PeekableQueue.prototype.peek = function () {
      return this._queue[0];
    }
    
    // good
    class PeekableQueue extends Queue {
      peek() {
        return this._queue[0];
      }
    }
  • 9.3 方法可以回傳 this 幫助方法之間進行鏈結。

    // bad
    Jedi.prototype.jump = function () {
      this.jumping = true;
      return true;
    };
    
    Jedi.prototype.setHeight = function (height) {
      this.height = height;
    };
    
    const luke = new Jedi();
    luke.jump(); // => true
    luke.setHeight(20); // => undefined
    
    // good
    class Jedi {
      jump() {
        this.jumping = true;
        return this;
      }
    
      setHeight(height) {
        this.height = height;
        return this;
      }
    }
    
    const luke = new Jedi();
    
    luke.jump()
      .setHeight(20);
  • 9.4 可以寫一個 toString() 的方法,但是請確保它可以正常執行且沒有函式副作用。

    class Jedi {
      constructor(options = {}) {
        this.name = options.name || 'no name';
      }
    
      getName() {
        return this.name;
      }
    
      toString() {
        return `Jedi - ${this.getName()}`;
      }
    }
  • *9.5 若類別沒有指定建構子,那它會擁有預設的建構子。一個空的建構子函式或是只委派給父類別的函式是不必要的。no-useless-constructor(todo)

    // bad
    class Jedi {
      constructor() {}
    
      getName() {
        return this.name;
      }
    }
    
    // bad
    class Rey extends Jedi {
      constructor(...args) {
        super(...args);
      }
    }
    
    // good
    class Rey extends Jedi {
      constructor(...args) {
        super(...args);
        this.name = 'Rey';
      }
    }
  • 9.6 避免出現完全一樣的類別成員。eslint: no-dupe-class-members

    為什麼?完全一樣的類別成員只有最後一次宣告的是有效的。有完全一樣的成員基本上已經能稱為是一個bug了。

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

⬆ 回到頂端

模組

  • 10.1 總是使用模組(import/export)勝過一個非標準模組的系統。你可以編譯為喜歡的模組系統。

    為什麼?模組就是未來的趨勢,讓我們現在就開始前往未來吧。

    // bad
    const AirbnbStyleGuide = require('./AirbnbStyleGuide');
    module.exports = AirbnbStyleGuide.es6;
    
    // ok
    import AirbnbStyleGuide from './AirbnbStyleGuide';
    export default AirbnbStyleGuide.es6;
    
    // best
    import { es6 } from './AirbnbStyleGuide';
    export default es6;
  • 10.2 請別使用萬用(通配, wildcard)字元引入。

    為什麼?這樣能夠確保你只有一個預設導出。

    // bad
    import * as AirbnbStyleGuide from './AirbnbStyleGuide';
    
    // good
    import AirbnbStyleGuide from './AirbnbStyleGuide';
  • 10.3 然後也不要在引入的地方導出。

    為什麼?雖然一行程式相當的簡明,但是讓引入及導出各自有明確的方式能夠讓事情保持一致。

    // bad
    // filename es6.js
    export { es6 as default } from './airbnbStyleGuide';
    
    // good
    // filename es6.js
    import { es6 } from './AirbnbStyleGuide';
    export default es6;
  • 10.4 同一個路徑在同一個地方只會引入一次。eslint: no-duplicate-imports

    為什麼?在多行下引入對同一個路徑進行引入會讓程式難以維護

    // bad
    import foo from 'foo';
    // … some other imports … //
    import { named1, named2 } from 'foo';
    
    // good
    import foo, { named1, named2 } from 'foo';
    
    // good
    import foo, {
      named1,
      named2,
    } from 'foo';
  • 10.5 不要導出可變的繫結(綁定)。eslint: import/no-mutable-exports

    為什麼?一般會盡量避免變數的存在,尤其是在導出變數這塊。可能這種做法在一些特殊的情況下會被用到,但通常來說,只有常數才能被導出。

    // bad
    let foo = 3;
    export { foo };
    
    // good
    const foo = 3;
    export { foo };
  • 10.6 如果模組中只有一個導出,相比去命名導出�的模組,不如直接設為default。eslint: import/prefer-default-export

    為什麼?這樣能鼓勵更多的文件只往外導出一個東西,讓整個項目更具可讀性和可維護性。

    // bad
    export function foo() {}
    
    // good
    export default function foo() {}
  • 10.7 把所有的 import 置於頂部。eslint: import/first

    為什麼?因為import會被提升(hoisted),將它們保持在頂部能防止一些意外的行為

    // bad
    import foo from 'foo';
    foo.init();
    
    import bar from 'bar';
    
    // good
    import foo from 'foo';
    import bar from 'bar';
    
    foo.init();
  • 10.8 多項的引入應該寫成像多行的陣列和物件字面量

    為什麼?The curly braces follow the same indentation rules as every other curly brace block in the style guide, as do the trailing commas.

    // bad
    import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';
    
    // good
    import {
      longNameA,
      longNameB,
      longNameC,
      longNameD,
      longNameE,
    } from 'path';
  • 10.9 不允許在模組的引入陳述中用Webpack loader的語法。eslint: import/no-webpack-loader-syntax

    為什麼?Since using Webpack syntax in the imports couples the code to a module bundler. Prefer using the loader syntax in webpack.config.js

    // bad
    import fooSass from 'css!sass!foo.scss';
    import barCss from 'style!css!bar.css';
    
    // good
    import fooSass from 'foo.scss';
    import barCss from 'bar.css';

⬆ 回到頂端

迭代器及產生器

  • 11.1 不要使用迭代器。更好的做法是使用 JavaScript 的高階函式,像是 map()reduce(),替代如 for-of 的迴圈語法。eslint: no-iterator no-restricted-syntax

    為什麼?這加強了我們不變的規則。處理純函式的回傳值讓程式碼更易讀,勝過它所造成的函式副作用。

    map() / every() / filter() / find() / findIndex() / reduce() / some() /...來迭代陣列,用 Object.keys() / Object.values() / Object.entries() 來產生陣列,這樣你也能迭代物件了。

    const numbers = [1, 2, 3, 4, 5];
    
    // bad
    let sum = 0;
    for (let num of numbers) {
      sum += num;
    }
    
    sum === 15;
    
    // good
    let sum = 0;
    numbers.forEach(num => sum += num);
    sum === 15;
    
    // best (使用 javascript 的高階函式)
    const sum = numbers.reduce((total, num) => total + num, 0);
    sum === 15;
    
    // bad
    const increasedByOne = [];
    for (let i = 0; i < numbers.length; i++) {
      increasedByOne.push(numbers[i] + 1);
    }
    
    // good
    const increasedByOne = [];
    numbers.forEach((num) => {
      increasedByOne.push(num + 1);
    });
    
    // best (keeping it functional)
    const increasedByOne = numbers.map(num => num + 1);
  • 11.2 現在還不要使用產生器。

    為什麼?因為它現在編譯至 ES5 還沒有編譯得非常好。

  • 11.3 如果你必須要用產生器,或是你無視了我們的建議,那至少確保它們的函數簽名中的空格是正確的。

    為什麼? function* 在概念上是一個關鍵字。 *不是要修飾 function 的。 function* 是一個唯一存在的建構子,它不同於 function

    // bad
    function * foo() {
      // ...
    }
    
    // bad
    const bar = function * () {
      // ...
    };
    
    // bad
    const baz = function *() {
      // ...
    };
    
    // bad
    const quux = function*() {
      // ...
    };
    
    // bad
    function*foo() {
      // ...
    }
    
    // bad
    function *foo() {
      // ...
    }
    
    // very bad
    function
    *
    foo() {
      // ...
    }
    
    // very bad
    const wat = function
    *
    () {
      // ...
    };
    
    // good
    function* foo() {
      // ...
    }
    
    // good
    const foo = function* () {
      // ...
    };

⬆ 回到頂端

屬性

  • 12.1 使用點 . 來存取屬性。eslint: dot-notation jscs: requireDotNotation

    const luke = {
      jedi: true,
      age: 28,
    };
    
    // bad
    const isJedi = luke['jedi'];
    
    // good
    const isJedi = luke.jedi;
  • 12.2 需要帶參數存取屬性時請使用中括號 []

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

  • 12.3 計算乘方時,用乘方運算子 ** 。eslit: no-restricted-properties

    // bad
    const binary = Math.pow(2, 10);
    
    // good
    const binary = 2 ** 10;

⬆ 回到頂端

變數

  • 13.1 為了避免污染全域的命名空間,請使用 const 來宣告變數,如果不這麼做將會產生全域變數。Captain Planet warned us of that. eslint: no-undef prefer-const

    // bad
    superPower = new SuperPower();
    
    // good
    const superPower = new SuperPower();
  • 13.2 每個變數只使用一個 constlet 來宣告。eslint: one-var

    為什麼?因為這樣更容易增加新的變數宣告,而且你也不用擔心替換 ;, 及加入的標點符號不同的問題。你也可以一個一個進行debugger,而不是直接一次跳過它們全部。

    // bad
    const items = getItems(),
        goSportsTeam = true,
        dragonball = 'z';
    
    // bad
    // (比較上述例子找出錯誤)
    const items = getItems(),
        goSportsTeam = true;
        dragonball = 'z';
    
    // good
    const items = getItems();
    const goSportsTeam = true;
    const dragonball = 'z';
  • 13.3 將所有的 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;
  • 13.4 在你需要的地方賦值給變數,但是請把它們放在合理的位置。

    為什麼?因為 letconst 是在區塊作用域內,而不是函式作用域。

    // bad - unnecessary function call
    function checkName(hasName) {
      const name = getName();
    
      if (hasName === 'test') {
        return false;
      }
    
      if (name === 'test') {
        this.setName('');
        return false;
      }
    
      return name;
    }
    
    // good
    function checkName(hasName) {
      if (hasName === 'test') {
        return false;
      }
    
      const name = getName();
    
      if (name === 'test') {
        this.setName('');
        return false;
      }
    
      return name;
    }
  • 13.5 不要把變數的宣告連結起來。eslint: no-multi-assign

    為什麼?這種連結起來的宣告方式會生成隱式的全局變數。

    // bad
    (function example() {
      // JavaScript interprets this as
      // let a = ( b = ( c = 1 ) );
      // The let keyword only applies to variable a; variables b and c become
      // global variables.
      let a = b = c = 1;
    }());
    
    console.log(a); // throws ReferenceError
    console.log(b); // 1
    console.log(c); // 1
    
    // good
    (function example() {
      let a = 1;
      let b = a;
      let c = a;
    }());
    
    console.log(a); // throws ReferenceError
    console.log(b); // throws ReferenceError
    console.log(c); // throws ReferenceError
    
    // the same applies for `const`
  • 13.6 避免使用一元的自增自減符( ++-- )。eslint: no-plusplus

    為什麼?Per the eslint documentation, unary increment and decrement statements are subject to automatic semicolon insertion and can cause silent errors with incrementing or decrementing values within an application. It is also more expressive to mutate your values with statements like num += 1 instead of num++ or num ++. Disallowing unary increment and decrement statements also prevents you from pre-incrementing/pre-decrementing values unintentionally which can also cause unexpected behavior in your programs.

    // 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;
  • 13.7 在賦值語句中,避免在 = 前或後進行換行.如果你的賦值違反了 max-len,那就在兩邊加上括號。

    為什麼? = 兩邊的換行會讓要賦的值變的混淆。

    // bad
    const foo =
      superLongLongLongLongLongLongLongLongFunctionName();
    
    // bad
    const foo
      = 'superLongLongLongLongLongLongLongLongString';
    
    // good
    const foo = (
      superLongLongLongLongLongLongLongLongFunctionName()
    );
    
    // good
    const foo = 'superLongLongLongLongLongLongLongLongString';

⬆ 回到頂端

提升

  • 14.1 var 宣告可以被提升至該作用域的最頂層,但賦予的值並不會。constlet 的宣告被賦予了新的概念,稱為暫時性死區(Temporal Dead Zones, TDZ)。這對於瞭解為什麼 typeof 不再那麼安全是相當重要的。

    // 我們知道這樣是行不通的
    // (假設沒有名為 notDefined 的全域變數)
    function example() {
      console.log(notDefined); // => throws a ReferenceError
    }
    
    // 由於變數提升的關係,
    // 你在引用變數後再宣告變數是行得通的。
    // 注:賦予給變數的 `true` 並不會被提升。
    function example() {
      console.log(declaredButNotAssigned); // => undefined
      var declaredButNotAssigned = true;
    }
    
    // 直譯器會將宣告的變數提升至作用域的最頂層,
    // 表示我們可以將這個例子改寫成以下:
    function example() {
      let declaredButNotAssigned;
      console.log(declaredButNotAssigned); // => undefined
      declaredButNotAssigned = true;
    }
    
    // 使用 const 及 let
    function example() {
      console.log(declaredButNotAssigned); // => throws a ReferenceError
      console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
      const declaredButNotAssigned = true;
    }
  • 14.2 賦予匿名函式的變數會被提升,但函式內容並不會。

    function example() {
      console.log(anonymous); // => undefined
    
      anonymous(); // => TypeError anonymous is not a function
    
      var anonymous = function () {
        console.log('anonymous function expression');
      };
    }
  • 14.3 賦予命名函式的變數會被提升,但函式內容及函式名稱並不會。

    function example() {
      console.log(named); // => undefined
    
      named(); // => TypeError named is not a function
    
      superPower(); // => ReferenceError superPower is not defined
    
      var named = function superPower() {
        console.log('Flying');
      };
    }
    
    // 當函式名稱和變數名稱相同時也是如此。
    function example() {
      console.log(named); // => undefined
    
      named(); // => TypeError named is not a function
    
      var named = function named() {
        console.log('named');
      }
    }
  • 14.4 宣告函式的名稱及函式內容都會被提升。

    function example() {
      superPower(); // => Flying
    
      function superPower() {
        console.log('Flying');
      }
    }
  • 想瞭解更多訊息,請參考 Ben CherryJavaScript Scoping & Hoisting

⬆ 回到頂端

條件式與等號

Comparison Operators & Equality

  • 15.1 請使用 ===!== ,別使用 ==!= 。eslint: eqeqeq

  • 15.2 像是 if 的條件語法內會使用 ToBoolean 的抽象方法強轉類型,並遵循以下規範:

    • 物件 轉換為 true
    • Undefined 轉換為 false
    • Null 轉換為 false
    • 布林 轉換為 該布林值
    • 數字 如果是 +0, -0, 或 NaN 則轉換為 false,其他的皆為 true
    • 字串 如果是空字串 '' 則轉換為 false,其他的皆為 true
    if ([0] && []) {
      // true
      // 陣列(即使為空)為一個物件,所以轉換為 true
    }
  • 15.3 對布林值,使用簡短的方式。對字串和數字要明確的寫出判斷式

    // bad
    if (isValid === true) {
      // ...
    }
    
    // good
    if (isValid) {
      // ...
    }
    
    // bad
    if (name) {
      // ...
    }
    
    // good
    if (name !== '') {
      // ...
    }
    
    // bad
    if (collection.length > 0) {
      // ...stuff...
    }
    
    // good
    if (collection.length) {
      // ...stuff...
    }
  • 15.4 想瞭解更多訊息請參考 Angus Croll 的 Truth Equality and JavaScript

  • 15.5 casedefault 包含了宣告語法(例如:letconstfunctionclass)時使用大括號來建立區塊。eslint: no-case-declarations

    為什麼?宣告語法可以在整個 switch 區塊中可見,但是只在進入該 case 時初始化。當多個 case 語法時會導致嘗試定義相同事情的問題。

    // bad
    switch (foo) {
      case 1:
        let x = 1;
        break;
      case 2:
        const y = 2;
        break;
      case 3:
        function f() {}
        break;
      default:
        class C {}
    }
    
    // good
    switch (foo) {
      case 1: {
        let x = 1;
        break;
      }
      case 2: {
        const y = 2;
        break;
      }
      case 3: {
        function f() {}
        break;
      }
      case 4:
        bar();
        break;
      default: {
        class C {}
      }
    }
  • 15.6 不應該使用巢狀的三元運算子,且通常應該使用單行來表示。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;
  • 15.7 避免不必要的三元運算子語法。eslint: no-unneedded-ternary

    // bad
    const foo = a ? a : b;
    const bar = c ? true : false;
    const baz = c ? false : true;
    
    // good
    const foo = a || b;
    const bar = !!c;
    const baz = !c;
  • 15.8 當混合使用運算符時,用括號把它們包起來。但若是只混用了標準算術運算子( + , - , * , / )就沒有必要,因為這四個的運算優先級很清楚明白。eslint: no-mixed-operators

    為什麼?這樣能提升程式的可讀性並能理清開發人員的意圖。

    // bad
    const foo = a && b < 0 || c > 0 || d + 1 === 0;
    
    // bad
    const bar = a ** b - 5 % d;
    
    // bad
    // one may be confused into thinking (a || b) && c
    if (a || b && c) {
      return d;
    }
    
    // good
    const foo = (a && b < 0) || c > 0 || (d + 1 === 0);
    
    // good
    const bar = (a ** b) - (5 % d);
    
    // good
    if (a || (b && c)) {
      return d;
    }
    
    // good
    const bar = a + b / c * d;

⬆ 回到頂端

區塊

  • 16.1 多行區塊請使用大括號刮起來。

    // bad
    if (test)
      return false;
    
    // good
    if (test) return false;
    
    // good
    if (test) {
      return false;
    }
    
    // bad
    function foo() { return false; }
    
    // good
    function bar() {
      return false;
    }
  • 16.2 如果你使用 ifelse 的多行區塊,請將 else 放在 if 區塊的結尾大括號後。eslint: brace-style

    // bad
    if (test) {
      thing1();
      thing2();
    }
    else {
      thing3();
    }
    
    // good
    if (test) {
      thing1();
      thing2();
    } else {
      thing3();
    }
  • *16.3 If an if block always executes a return statement, the subsequent else block is unnecessary. A return in an else if block following an if block that contains a return can be separated into multiple if blocks. eslint: no-else-return(todo)

    // bad
    function foo() {
      if (x) {
        return x;
      } else {
        return y;
      }
    }
    
    // bad
    function cats() {
      if (x) {
        return x;
      } else if (y) {
        return y;
      }
    }
    
    // bad
    function dogs() {
      if (x) {
        return x;
      } else {
        if (y) {
          return y;
        }
      }
    }
    
    // good
    function foo() {
      if (x) {
        return x;
      }
    
      return y;
    }
    
    // good
    function cats() {
      if (x) {
        return x;
      }
    
      if (y) {
        return y;
      }
    }
    
    // good
    function dogs(x) {
      if (x) {
        if (z) {
          return y;
        }
      } else {
        return z;
      }
    }

⬆ 回到頂端

## 控制敘述
  • 17.1 當你的控制敘述( if , while 等)太長甚至是超過了一行的最長長度時,其中的每一塊(邏輯判斷式)可以自成一行,並把邏輯運算子放在行首。

    為什麼?要求把邏輯運算子放在行首,一是為了讓運算子之間對齊,二是參照了方法鏈的形式(方法鏈過長時,每個方法會自成一行,並把 . 放在行首)。並且這樣做後即使參雜有複雜的邏輯也能在一定程度上提升可讀性。

    // bad
    if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
      thing1();
    }
    
    // bad
    if (foo === 123 &&
      bar === 'abc') {
      thing1();
    }
    
    // bad
    if (foo === 123
      && bar === 'abc') {
      thing1();
    }
    
    // bad
    if (
      foo === 123 &&
      bar === 'abc'
    ) {
      thing1();
    }
    
    // good
    if (
      foo === 123
      && bar === 'abc'
    ) {
      thing1();
    }
    
    // good
    if (
      (foo === 123 || bar === 'abc')
      && doesItLookGoodWhenItBecomesThatLong()
      && isThisReallyHappening()
    ) {
      thing1();
    }
    
    // good
    if (foo === 123 && bar === 'abc') {
      thing1();
    }
  • 17.2 使用控制敘述取代用邏輯運算子進行控制

    // bad
    !isRunning && startRunning();
    
    // good
    if (!isRunning) {
      startRunning();
    }

⬆ 回到頂端

註解

  • 18.1 多行註解請使用 /** ... */ ,包含描述,指定類型以及參數值還有回傳值。

    // bad
    // make() 根據傳入的 tag 名稱回傳一個新的元件
    //
    // @param {String} tag
    // @return {Element} element
    function make(tag) {
    
      // ...stuff...
    
      return element;
    }
    
    // good
    /**
     * make() 根據傳入的 tag 名稱回傳一個新的元件
     *
     * @param {String} tag
     * @return {Element} element
     */
    function make(tag) {
    
      // ...stuff...
    
      return element;
    }
  • 18.2 單行註解請使用 //。在欲註解的上方新增一行進行註解。在註解的上方空一行,除非他在區塊的第一行。

    // bad
    const active = true;  // 當目前分頁
    
    // good
    // is current tab
    const active = true;
    
    // bad
    function getType() {
      console.log('fetching type...');
      // 設定預設的類型為 'no type'
      const type = this._type || 'no type';
    
      return type;
    }
    
    // good
    function getType() {
      console.log('fetching type...');
    
      // 設定預設的類型為 'no type'
      const type = this._type || 'no type';
    
      return type;
    }
    
    // also good
    function getType() {
      // set the default type to 'no type'
      const type = this._type || 'no type';
    
      return type;
    }
  • 18.3 在開始註解前先放一個空格,讓註解讀起來更容易。eslint: spaced-comment

    // bad
    //is current tab
    const active = true;
    
    // good
    // is current tab
    const active = true;
    
    // bad
    /**
     *make() returns a new element
     *based on the passed-in tag name
     */
    function make(tag) {
    
      // ...
    
      return element;
    }
    
    // good
    /**
     * make() returns a new element
     * based on the passed-in tag name
     */
    function make(tag) {
    
      // ...
    
      return element;
    }
  • 18.4 在註解前方加上 FIXMETODO 可以幫助其他開發人員快速瞭解這是一個需要重新討論的問題,或是一個等待解決的問題。和一般的註解不同,他們是可被執行的。對應的動作為 FIXME -- 重新討論並解決TODO -- 必須執行

  • 18.5 使用 // FIXME: 標注問題。

    class Calculator extends Abacus {
      constructor() {
        super();
    
        // FIXME: 不該在這使用全域變數
        total = 0;
      }
    }
  • 18.6 使用 // TODO: 標注問題的解決方式。

    class Calculator extends Abacus {
      constructor() {
        super();
    
        // TODO: total 應該可被傳入的參數所修改
        this.total = 0;
      }
    }

⬆ 回到頂端

空格

  • 19.1 將 Tab 設定為兩個空格。eslint: indent

    // bad
    function foo() {
    ∙∙∙∙const name;
    }
    
    // bad
    function bar() {
    ∙const name;
    }
    
    // good
    function baz() {
    ∙∙const name;
    }
  • 19.2 在大括號前加一個空格。eslint: space-before-blocks

    // bad
    function test(){
      console.log('test');
    }
    
    // good
    function test() {
      console.log('test');
    }
    
    // bad
    dog.set('attr',{
      age: '1 year',
      breed: 'Bernese Mountain Dog',
    });
    
    // good
    dog.set('attr', {
      age: '1 year',
      breed: 'Bernese Mountain Dog',
    });
  • 19.3 在控制流程的語句(if, while 等等。)的左括號前加上一個空格。宣告的函式和傳入的變數間則沒有空格。eslint: keyword-spacing

    // bad
    if(isJedi) {
      fight ();
    }
    
    // good
    if (isJedi) {
      fight();
    }
    
    // bad
    function fight () {
      console.log ('Swooosh!');
    }
    
    // good
    function fight() {
      console.log('Swooosh!');
    }
  • 19.4 將運算子用空格隔開。eslint: space-infix-ops

    // bad
    const x=y+5;
    
    // good
    const x = y + 5;
  • 19.5 在檔案的最尾端加上一行空白行。eslint: eol-last

    // bad
    (function (global) {
      // ...stuff...
    })(this);
    // bad
    (function (global) {
      // ...stuff...
    })(this);
    
    // good
    (function (global) {
      // ...stuff...
    })(this);
  • 19.6 當有個較長的方法鏈(大於兩個)時請換行縮排。利用前面的 . 強調該行是呼叫方法,而不是一個新的宣告。eslint: newline-per-chained-call no-whitespace-before-property

    // bad
    $('#items').find('.selected').highlight().end().find('.open').updateCount();
    
    // bad
    $('#items').
      find('.selected').
        highlight().
        end().
      find('.open').
        updateCount();
    
    // good
    $('#items')
      .find('.selected')
        .highlight()
        .end()
      .find('.open')
        .updateCount();
    
    // bad
    const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
        .attr('width', (radius + margin) * 2).append('svg:g')
        .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
        .call(tron.led);
    
    // good
    const leds = stage.selectAll('.led')
        .data(data)
      .enter().append('svg:svg')
        .classed('led', true)
        .attr('width', (radius + margin) * 2)
      .append('svg:g')
        .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
        .call(tron.led);
    
    // good
    const leds = stage.selectAll('.led').data(data);
  • 19.7 在區塊的結束及下個敘述間加上空行。

    // bad
    if (foo) {
      return bar;
    }
    return baz;
    
    // good
    if (foo) {
      return bar;
    }
    
    return baz;
    
    // bad
    const obj = {
      foo() {
      },
      bar() {
      },
    };
    return obj;
    
    // good
    const obj = {
      foo() {
      },
    
      bar() {
      },
    };
    
    return obj;
    
    // bad
    const arr = [
      function foo() {
      },
      function bar() {
      },
    ];
    return arr;
    
    // good
    const arr = [
      function foo() {
      },
    
      function bar() {
      },
    ];
    
    return arr;
  • 19.8 別在區塊中置放空行。eslint: padded-blocks

    // bad
    function bar() {
    
      console.log(foo);
    
    }
    
    // also bad
    if (baz) {
    
      console.log(qux);
    } else {
      console.log(foo);
    
    }
    
    // good
    function bar() {
      console.log(foo);
    }
    
    // good
    if (baz) {
      console.log(qux);
    } else {
      console.log(foo);
    }
  • 19.9 不要在括號內的兩側置放空格。eslint: space-in-parens

    // bad
    function bar( foo ) {
      return foo;
    }
    
    // good
    function bar(foo) {
      return foo;
    }
    
    // bad
    if ( foo ) {
      console.log(foo);
    }
    
    // good
    if (foo) {
      console.log(foo);
    }
  • 19.10 不要在中括號內的兩側置放空格。eslint: array-bracket-spacing

    // bad
    const foo = [ 1, 2, 3 ];
    console.log(foo[ 0 ]);
    
    // good
    const foo = [1, 2, 3];
    console.log(foo[0]);
  • 19.11 在大括號內的兩側置放空格。eslint: object-curly-spacing

    // bad
    const foo = {clark: 'kent'};
    
    // good
    const foo = { clark: 'kent' };
  • 19.12 避免一行的程式碼超過 100 字元(包含空白)。注意,前面提到的長字串不適用這條規定,它不應該被分開來。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(() => console.log('Congratulations!'))
      .fail(() => console.log('You have failed this city.'));

  • 19.13 區塊的前(後)大括號若與後(前)一句語句在同一行,中間需要插入空格。eslint: block-spacing

    // bad
    function foo() {return true;}
    if (foo) { bar = 0;}
    
    // good
    function foo() { return true; }
    if (foo) { bar = 0; }

  • 19.14 在逗號前避免留有空格,在逗號後請留空格。eslint: comma-spacing

    // bad
    var foo = 1,bar = 2;
    var arr = [1 , 2];
    // good
    var foo = 1, bar = 2;
    var arr = [1, 2];
  • 19.15 物件被方括號包裹的計算屬性名,與方括號之間不要留有空格。eslint: computed-property-spacing

    // bad
    obj[foo ]
    obj[ 'foo']
    var x = {[ b ]: a}
    obj[foo[ bar ]]
    
    // good
    obj[foo]
    obj['foo']
    var x = { [b]: a }
    obj[foo[bar]]

  • 19.16 在函式名和它的調用之間不要留有空格。eslint: func-call-spacing

    // bad
    func ();
    
    func
    ();
    
    // good
    func();

  • 19.17 在物件的字面量語法中,物件的屬性值與屬性名的冒號間留有空格。eslint: key-spacing

    // bad
    var obj = { "foo" : 42 };
    var obj2 = { "foo":42 };
    // good
    var obj = { "foo": 42 };

  • 19.19 應避免多行空行,並在檔案的末尾留有一行空行。 eslint: no-multiple-empty-lines

    // bad
    var x = 1;
    
    
    
    var y = 2;
    
     // good
    var x = 1;
    
    var y = 2;

⬆ 回到頂端

逗號

  • 20.1 不要將逗號放在行首。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',
    };
  • 20.2 增加結尾的逗號:別懷疑。eslint: comma-dangle

    為什麼?這會讓 Git 的差異列表更乾淨。另外,Babel 轉譯器也會刪除結尾多餘的逗號,也就是說你完全不需要擔心在老舊的瀏覽器發生多餘逗號的問題

    // bad - 不含多餘逗號的 git 差異列表
    const hero = {
         firstName: 'Florence',
    -    lastName: 'Nightingale'
    +    lastName: 'Nightingale',
    +    inventorOf: ['coxcomb graph', 'modern nursing']
    };
    
    // good - 包含多餘逗號的 git 差異列表
    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
    function createHero(
      firstName,
      lastName,
      inventorOf
    ) {
      // does nothing
    }
    
    // good
    function createHero(
      firstName,
      lastName,
      inventorOf,
    ) {
      // does nothing
    }
    
    // good (note that a comma must not appear after a "rest" element)
    function createHero(
      firstName,
      lastName,
      inventorOf,
      ...heroArgs
    ) {
      // does nothing
    }
    
    // bad
    createHero(
      firstName,
      lastName,
      inventorOf
    );
    
    // good
    createHero(
      firstName,
      lastName,
      inventorOf,
    );
    
    // good (note that a comma must not appear after a "rest" element)
    createHero(
      firstName,
      lastName,
      inventorOf,
      ...heroArgs
    );

⬆ 回到頂端

分號

  • 21.1 對啦。。eslint: semi

    為什麼?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!
    function 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
    function foo() {
      return 'search your feelings, you know it to be foo';
    }

    瞭解更多

⬆ 回到頂端

型別轉換

  • 22.1 在開頭的宣告進行強制型別轉換。

  • 22.2 字串: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);
  • 22.3 數字:使用 Number 做型別轉換,而 parseInt 始終會帶上一個進制數來解析字串。eslint: radix no-new-wrappers

    const inputValue = '4';
    
    // bad
    const val = new Number(inputValue);
    
    // bad
    const val = +inputValue;
    
    // bad
    const val = inputValue >> 0;
    
    // bad
    const val = parseInt(inputValue);
    
    // good
    const val = Number(inputValue);
    
    // good
    const val = parseInt(inputValue, 10);
  • 22.4 如果你因為某個原因在做些瘋狂的事情,考慮到性能方面的原因 parseInt 不能解決你面臨的問題,最終你採用了位元運算子的方式的話,請留下註解解釋為什麼這樣做,以及你做了哪些事情。

    // good
    /**
     * 使用 parseInt 導致我的程式變慢,改成使用
     * 位元右移強制將字串轉為數字加快了他的速度。
     */
    const val = inputValue >> 0;
  • 22.5 **注意:**使用位元運算子的時候請小心。數字為 64 位元數值,但是使用位元轉換時則會回傳一個 32 位元的整數(來源),這會導致大於 32 位元的數值產生異常 討論串,32 位元的整數最大值為 2,147,483,647:

    2147483647 >> 0 //=> 2147483647
    2147483648 >> 0 //=> -2147483648
    2147483649 >> 0 //=> -2147483647
  • 22.6 布林:eslint: no-new-wrappers

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

⬆ 回到頂端

命名規則

  • 23.1 避免使用單一字母命名,讓你的命名具有含義。eslint: id-length

    // bad
    function q() {
      // ...
    }
    
    // good
    function query() {
      // ...
    }
  • 23.2 使用駝峰式大小寫命名物件,函式及實例。eslint: camelcase

    // bad
    const OBJEcttsssss = {};
    const this_is_my_object = {};
    function c() {}
    
    // good
    const thisIsMyObject = {};
    function thisIsMyFunction() {}
  • 23.3 使用帕斯卡命名法來命名建構子或類別。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',
    });
  • 23.4 不要在命名的前後帶下劃線。eslint: no-underscore-dangle

    為什麼?JavaScript does not have the concept of privacy in terms of properties or methods. Although a leading underscore is a common convention to mean “private”, in fact, these properties are fully public, and as such, are part of your public API contract. This convention might lead developers to wrongly think that a change won’t count as breaking, or that tests aren’t needed. tl;dr: if you want something to be “private”, it must not be observably present.

    // bad
    this.__firstName__ = 'Panda';
    this.firstName_ = 'Panda';
    this._firstName = 'Panda';
    
    // good
    this.firstName = 'Panda';
    
    // good, in environments where WeakMaps are available
    // see https://kangax.github.io/compat-table/es6/#test-WeakMap
    const firstNames = new WeakMap();
    firstNames.set(this, 'Panda');
  • 23.5 請不要把 this 儲存為引用。請使用箭頭函式或是 Function#bind

    // bad
    function foo() {
      const self = this;
      return function () {
        console.log(self);
      };
    }
    
    // bad
    function foo() {
      const that = this;
      return function () {
        console.log(that);
      };
    }
    
    // good
    function foo() {
      return () => {
        console.log(this);
      };
    }
  • 23.6 檔案的名稱應該與默認導出的名稱相同。

    // 檔案1 內容
    class CheckBox {
      // ...
    }
    export default CheckBox;
    
    // 檔案2 內容
    export default function fortyTwo() { return 42; }
    
    // 檔案3 內容
    export default function insideDirectory() {}
    
    // 在其他檔案中
    // bad
    import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename
    import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export
    import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export
    
    // bad
    import CheckBox from './check_box'; // PascalCase import/export, snake_case filename
    import forty_two from './forty_two'; // snake_case import/filename, camelCase export
    import inside_directory from './inside_directory'; // snake_case import, camelCase export
    import index from './inside_directory/index'; // requiring the index file explicitly
    import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly
    
    // good
    import CheckBox from './CheckBox'; // PascalCase export/import/filename
    import fortyTwo from './fortyTwo'; // camelCase export/import/filename
    import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index"
    // 上面這條同時支持 insideDirectory.js 和 insideDirectory/index.js
  • 23.7 當你導出為預設的函式時請使用駝峰式大小寫。檔案名稱必須與你的函式名稱一致。

    function makeStyleGuide() {
    }
    
    export default makeStyleGuide;
  • 23.8 當你導出為建構子 / 類別 / 單例(單體) / 函式庫 / 空物件時請使用帕斯卡命名法。

    const AirbnbStyleGuide = {
      es6: {
      }
    };
    
    export default AirbnbStyleGuide;
  • 23.9 縮寫時要不保持全部大寫,要不就全部小寫。

    為什麼?名稱是用來給人看的,不是給電腦看的。

    // bad
    import SmsContainer from './containers/SmsContainer';
    
    // bad
    const HttpRequests = [
      // ...
    ];
    
    // good
    import SMSContainer from './containers/SMSContainer';
    
    // good
    const HTTPRequests = [
      // ...
    ];
    
    // also good
    const httpRequests = [
      // ...
    ];
    
    // best
    import TextMessageContainer from './containers/TextMessageContainer';
    
    // best
    const requests = [
      // ...
    ];
  • *23.10 You may optionally uppercase a constant only if it (1) is exported, (2) is a const (it can not be reassigned), and (3) the programmer can trust it (and its nested properties) to never change.(todo)

    為什麼?This is an additional tool to assist in situations where the programmer would be unsure if a variable might ever change. UPPERCASE_VARIABLES are letting the programmer know that they can trust the variable (and its properties) not to change.

    • What about all const variables? - This is unnecessary, so uppercasing should not be used for constants within a file. It should be used for exported constants however.
    • What about exported objects? - Uppercase at the top level of export (e.g. EXPORTED_OBJECT.key) and maintain that all nested properties do not change.
    // bad
    const PRIVATE_VARIABLE = 'should not be unnecessarily uppercased within a file';
    
    // bad
    export const THING_TO_BE_CHANGED = 'should obviously not be uppercased';
    
    // bad
    export let REASSIGNABLE_VARIABLE = 'do not use let with uppercase variables';
    
    // ---
    
    // allowed but does not supply semantic value
    export const apiKey = 'SOMEKEY';
    
    // better in most cases
    export const API_KEY = 'SOMEKEY';
    
    // ---
    
    // bad - unnecessarily uppercases key while adding no semantic value
    export const MAPPING = {
      KEY: 'value'
    };
    
    // good
    export const MAPPING = {
      key: 'value'
    };

⬆ 回到頂端

存取器

  • 24.1 屬性的存取器函式不是必須的。

  • 24.2 不要使用 JavaScript 的 getters 或 setters,因為它們會導致意想不到的副作用,而且不易於測試、維護以及進行推測。取而代之,如果你要建立一個存取器函式,請使用 getVal()setVal('hello')

    // bad
    class Dragon {
      get age() {
        // ...
      }
    
      set age(value) {
        // ...
      }
    }
    
    // good
    class Dragon {
      getAge() {
        // ...
      }
    
      setAge(value) {
        // ...
      }
    }
  • 24.3 如果屬性/方法回傳值是布林,請使用 isVal()hasVal()

    // bad
    if (!dragon.age()) {
      return false;
    }
    
    // good
    if (!dragon.hasAge()) {
      return false;
    }
  • 24.4 可以建立 get()set() 函式,但請保持一致。

    class Jedi {
      constructor(options = {}) {
        const lightsaber = options.lightsaber || 'blue';
        this.set('lightsaber', lightsaber);
      }
    
      set(key, val) {
        this[key] = val;
      }
    
      get(key) {
        return this[key];
      }
    }

⬆ 回到頂端

事件

  • 25.1 當需要對事件傳入資料時(不論是 DOM 事件或是其他私有事件),請用物件的字面值語法替代單一的值。這樣可以使之後的開發人員直接加入其他的資料到事件裡,而不需更新該事件的處理器。例如,比較不好的做法:

    // bad
    $(this).trigger('listingUpdated', listing.id);
    
    ...
    
    $(this).on('listingUpdated', (e, listingId) => {
      // do something with listingId
    });

    更好的做法:

    // good
    $(this).trigger('listingUpdated', { listingId: listing.id });
    
    ...
    
    $(this).on('listingUpdated', (e, data) => {
      // do something with data.listingId
    });

⬆ 回到頂端

jQuery

  • 26.1 jQuery封裝的物件請使用 $ 當前綴。

    // bad
    const sidebar = $('.sidebar');
    
    // good
    const $sidebar = $('.sidebar');
    
    // good
    const $sidebarBtn = $('.sidebar-btn');
  • 26.2 對jQuery 選擇器的查詢進行快取操作。

    // bad
    function setSidebar() {
      $('.sidebar').hide();
    
      // ...stuff...
    
      $('.sidebar').css({
        'background-color': 'pink'
      });
    }
    
    // good
    function setSidebar() {
      const $sidebar = $('.sidebar');
      $sidebar.hide();
    
      // ...stuff...
    
      $sidebar.css({
        'background-color': 'pink'
      });
    }
  • 26.3 DOM 的查詢請使用層遞的 $('.sidebar ul') 或 父元素 > 子元素 $('.sidebar > ul')jsPerf

  • 26.4 對 jQuery 物件作用域內的查詢,使用 find

    // bad
    $('ul', '.sidebar').hide();
    
    // bad
    $('.sidebar').find('ul').hide();
    
    // good
    $('.sidebar ul').hide();
    
    // good
    $('.sidebar > ul').hide();
    
    // good
    $sidebar.find('ul').hide();

⬆ 回到頂端

ECMAScript 5 相容性

⬆ 回到頂端

ECMAScript 6+ (ES 2015+) 風格

  • 28.1 以下是連結到各個 ES6 特性的列表。
  1. 箭頭函式
  2. 類別
  3. 物件簡寫
  4. 簡潔物件
  5. 可計算的物件屬性
  6. 模板字串
  7. 解構子
  8. 預設參數
  9. 剩餘參數(Rest)
  10. 陣列擴展
  11. Let 及 Const
  12. 乘方運算子
  13. 迭代器及產生器
  14. 模組

⬆ 回到頂端

測試

  • 30.1 如題。

    function foo() {
      return true;
    }
  • 30.2 無題,不過很重要

  • 不論你用哪個測試框架,你都應該撰寫測試!

  • 力求撰寫足夠多的純函式,並盡量減少異常發生的機會。

  • 要對 stubs 及 mocks 保持嚴謹——他們可以讓你的測試變得更加脆弱。

  • 我們在 Airbnb 主要使用 mocha。對小型或單獨的模組偶爾使用 tape

  • 努力達到 100% 的測試涵蓋率是個很好的目標,即使實現這件事是不切實際的。

  • 每當你修復完一個 bug,就撰寫回歸測試。一個修復完的 bug 若沒有回歸測試,通常在未來肯定會再次出問題。

⬆ 回到頂端

效能

⬆ 回到頂端

資源

學習 ES6

請讀這個

工具

其他的風格指南

其他風格

瞭解更多

書籍

部落格

Podcasts

⬆ 回到頂端

誰在使用

這是正在使用這份風格指南的組織列表。送一個 pull request 後我們會將你增加到列表上。

⬆ 回到頂端

翻譯

This style guide is also available in other languages:

JavaScript 風格指南

與我們討論 JavaScript

貢獻者

License

(The MIT License)

Copyright (c) 2014-2016 Airbnb

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

⬆ 回到頂端

Amendments

We encourage you to fork this guide and change the rules to fit your team's style guide. Below, you may list some amendments to the style guide. This allows you to periodically update your style guide without having to deal with merge conflicts.

部分詞彙翻譯對照(大部分詞彙參照JavaScript大全(O'REILLY))

  • argument: 引數
  • arrays: 陣列
  • assign: 指定
  • build: 建置
  • cache: 快取
  • call: 呼叫
  • character set: 字元集
  • class: 類別
  • copy:複製
  • comments: 註解
  • conditionals: 條件式
  • constructors: 建構子
  • declare: 宣告
  • define: 定義
  • escape characters: 轉譯字元(跳脫字元)
  • expression: 運算式
  • file: 檔案
  • function: 函式
  • global: 全域
  • hoisting: 提升
  • identifiers: 識別字
  • implicit: 隱性(隱含的)
  • instance: 實體
  • iteration: 迭代
  • interpreter: 直譯器
  • invoke: 調用
  • literal syntax: 字面值語法(實字語法)
  • lookup: 查詢(查對)
  • loop: 迴圈
  • map: 映射
  • module: 模組
  • mutable: 可變
  • nested: 嵌套(巢套)
  • numeric: 數值
  • object: 物件
  • operator: 運算子
  • package: 套件
  • parameter: 參數
  • parse: 解析
  • pattern matching: 範式對比(正規比對)
  • plugin: 外掛(插件)
  • processes: 行程(進程)
  • properties: 屬性(特性)
  • prototype chain: 原型鏈
  • reassign: 重新指派(再指派)
  • reference: 參考
  • regression test: 回歸測試
  • regular expressions: 正規運算式
  • rest operator: 其餘運算子
  • return: 回傳
  • runtime: 執行期
  • scope: 範疇
  • shallow-copy: 淺拷貝
  • spread operator: 展開運算子
  • statements: 述句(陳述句)
  • superset: 超集
  • thread: 執行緒(線程)
  • types: 型別
  • values: 運算值(值)
  • variable: 變數

About

Airbnb JavaScript Style Guide 個人翻譯版

Topics

Resources

Stars

Watchers

Forks