Airbnb前端規範之javascript編碼規範
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編碼規範