1. 程式人生 > >Airbnb前端規範之javascript編碼規範

Airbnb前端規範之javascript編碼規範

傳遞 ++ ack ice 必須 轉換 cat eal 快速

1 引用

1.1 對所有的引用使用 const ,不要使用 var。

(這能確保你無法對引用重新賦值,也不會導致出現 bug 或難以理解)

// bad
  var a = 1;
  var b = 2;

// good
  const a = 1;
  const b = 2;

1.2 如果一定需要可變動的引用,使用 let 代替 var。

(因為 let 是塊級作用域,而 var 是函數作用域。)

// bad
  var count = 1;
  if (true) {
    count += 1;
  }

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

2 對象

2.1 使用字面值創建對象。

// bad
const item = new Object();

// good
const item = {};

2.2 使用對象方法的簡寫。

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

2.3 使用對象屬性值的簡寫。

const lukeSkywalker = ‘Luke Skywalker‘;
// bad
  const obj = {
    lukeSkywalker: lukeSkywalker,
  };
// good
  const obj = {
    lukeSkywalker,
  };

2.4 不要直接調用 Object.prototype 的方法,如:hasOwnProperty, propertyIsEnumerable, 和 isPrototypeOf

// 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 */
const has = require(‘has‘);
…
console.log(has.call(object, key));

2.5 淺拷貝對象的時候最好是使用 … 操作符而不是 Object.assign

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

3 數組

3.1 使用字面值創建數組。eslint: no-array-constructor

// bad
const items = new Array();

// good
const items = [];

3.2 使用拓展運算符 … 復制數組。

// bad
const items = new Array();

// good
const items = [];

// bad
const len = items.length;
const itemsCopy = [];
let i;

for(i = 0;i <len;i++){
  itemsCopy[i] = items[i];
}

// good
const itemsCopy = [...items];

3.3 使用 Array#from 把一個類數組對象轉換成數組

const foo = document.querySelectorAll(‘.foo‘);
const nodes = Array.from(foo);

4 函數

4.1 使用函數聲明代替函數表達式

為什麽?因為函數聲明是可命名的,所以他們在調用棧中更容易被識別。此外,函數聲明會把整個函數提升(hoisted),而函數表達式只會把函數的引用變量名提升。這條規則使得箭頭函數可以取代函數表達式。

// bad
  const foo = function () {
  };

  // good
  function foo() {
  }

4.2 函數表達式:

// 立即調用的函數表達式 (IIFE)
(() => {
   console.log(‘Welcome to the Internet. Please follow me.‘);
})();

4.3 永遠不要在一個非函數代碼塊(if、while 等)中聲明一個函數,把那個函數賦給一個變量。瀏覽器允許你這麽做,但它們的解析表現不一致

// bad
if (currentUser) {
  function test() {
    console.log(‘Nope.‘);
  }
}

// good
let test;
if (currentUser) {
  test = () => {
    console.log(‘Yup.‘);
  };
}

4.4 不要使用 arguments。可以選擇 rest 語法 … 替代

為什麽?使用 … 能明確你要傳入的參數。另外 rest 參數是一個真正的數組,而 arguments 是一個類數組。

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

  // good
  function concatenateAll(...args) {
    return args.join(‘‘);
  }

5 箭頭函數

5.1 當你必須使用函數表達式(或傳遞一個匿名函數)時,使用箭頭函數符號。

為什麽?因為箭頭函數創造了新的一個 this 執行環境(譯註:參考 Arrow functions - JavaScript | MDN 和 ES6 arrow functions, syntax and lexical scoping),通常情況下都能滿足你的需求,而且這樣的寫法更為簡潔。

為什麽不?如果你有一個相當復雜的函數,你或許可以把邏輯部分轉移到一個函數聲明上。

// bad
  [1, 2, 3].map(function (x) {
    return x * x;
  });

  // good
  [1, 2, 3].map((x) => {
    return x * x;
  });

5.2 如果一個函數適合用一行寫出並且只有一個參數,那就把花括號、圓括號和 return 都省略掉。如果不是,那就不要省略

為什麽?語法糖。在鏈式調用中可讀性很高。
為什麽不?當你打算回傳一個對象的時候。

  // good
  [1, 2, 3].map(x => x * x);

  // good
  [1, 2, 3].reduce((total, n) => {
    return total + n;
  }, 0);

6 構造器

6.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;
    }
  }

  

6.2 使用 extends 繼承。

為什麽?因為 extends 是一個內建的原型繼承方法並且不會破壞 instanceof。

6.3 方法可以返回 this 來幫助鏈式調用。

7 模塊

7.1 總是使用模組 (import/export)

7.2 不要使用通配符 import

// bad
  import * as AirbnbStyleGuide from ‘./AirbnbStyleGuide‘;

// good
  import AirbnbStyleGuide from ‘./AirbnbStyleGuide‘;

  

7.3 不要從 import 中直接 export

// bad
  // filename es6.js
  export { es6 as default } from ‘./airbnbStyleGuide‘;

// good
  // filename es6.js
  import { es6 } from ‘./AirbnbStyleGuide‘;
  export default es6;

  

8 Iterators and Generators

8.1 不要使用 iterators,使用高階函數例如 map() 和 reduce() 替代 for-of

為什麽?這加強了我們不變的規則。處理純函數的回調值更易讀,這比它帶來的副作用更重要。

 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 (use the functional force)
  const sum = numbers.reduce((total, num) => total + num, 0);
  sum === 15;

8.2 現在還不要使用 generators?

為什麽?因為它們現在還沒法很好地編譯到 ES5。 (目前Chrome 和 Node.js 的穩定版本都已支持 generators)

9 變量

9.1 一直使用 const 來聲明變量

如果不這樣做就會產生全局變量。我們需要避免全局命名空間的汙染。

// bad
superPower = new SuperPower();

// good
const superPower = new SuperPower();

  

9.2 使用 const 聲明每一個變量

為什麽?增加新變量將變的更加容易,而且你永遠不用再擔心調換錯 ; 跟 ,。

9.3 將所有的 const 和 let 分組

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

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

9.4 在你需要的地方給變量賦值,但請把它們放在一個合理的位置

let 和 const 是塊級作用域而不是函數作用域。

10 提升

10.1 var 聲明會被提升至該作用域的頂部,但它們賦值不會提升。

let 和 const 被賦予了一種稱為「暫時性死區(Temporal Dead Zones, TDZ)」的概念。這對於了解為什麽 type of 不再安全相當重要。

10.2 匿名函數表達式的變量名會被提升,但函數內容並不會。

10.3 命名的函數表達式的變量名會被提升,但函數名和函數函數內容並不會。

10.4 函數聲明的名稱和函數體都會被提升。

11 比較運算符 & 等號

11.1 優先使用 === 和 !== 而不是 == 和 !=.

11.2 條件表達式例如 if 語句通過抽象方法 ToBoolean 強制計算它們的表達式並且總是遵守下面的規則:

o 對象 被計算為 true
o Undefined 被計算為 false
o Null 被計算為 false
o 布爾值 被計算為 布爾的值
o 數字 如果是 +0、-0、或 NaN 被計算為 false, 否則為 true
o 字符串 如果是空字符串 ” 被計算為 false,否則為 true

12 註釋

12.1 使用 /* … / 作為多行註釋。包含描述、指定所有參數和返回值的類型和值。

// bad
// make() returns a new element
// based on the passed in tag name
//
// @param {String} tag
// @return {Element} element
function make(tag) {

  // ...stuff...

  return element;
}

// good
/**
 * make() returns a new element
 * based on the passed in tag name
 *
 * @param {String} tag
 * @return {Element} element
 */
function make(tag) {

  // ...stuff...

  return element;
}

  

12.2 使用 // 作為單行註釋。在註釋對象上面另起一行使用單行註釋。在註釋前插入空行。

12.3 給註釋增加 FIXME 或 TODO 的前綴

幫助其他開發者快速了解這是一個需要復查的問題,或是給需要實現的功能提供一個解決方式。這將有別於常見的註釋,因為它們是可操作的。使用 FIXME – need to figure this out 或者 TODO – need to implement。

12.4 使用 // FIXME: 標註問題。

class Calculator {
  constructor() {
    // FIXME: shouldn‘t use a global here
    total = 0;
  }
}

  

12.5 使用 // TODO: 標註問題的解決方式。

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

13 空白

13.1 使用 2 個空格作為縮進。

13.2 在花括號前要放一個空格。

13.3 在控制語句(if、while 等)的小括號前放一個空格。

在函數調用及聲明中,不在函數的參數列表前加空格。

13.4 在文件末尾插入一個空行。

13.5 在使用長方法鏈時進行縮進。使用放置在前面的點 . 強調這是方法調用而不是新語句。

Airbnb前端規範之javascript編碼規範