更合理的方式寫 JavaScript
原文看 這里 ,收錄在此為便于查閱。
類型
-
1.1 基本類型:直接存取。
字符創(chuàng)
數(shù)值
布爾類型
null
undefined
const foo = 1; let bar = foo; bar = 9; console.log(foo, bar); // => 1, 9
-
1.2 復(fù)雜類型:通過引用的方式存取。
對象
數(shù)組
函數(shù)
const foo = [1, 2]; const bar = foo; bar[0] = 9; console.log(foo[0], bar[0]); // => 9,9
引用
-
2.1 對所有的引用類型使用
const
; 不要使用var
。為什么?這確保你無法對引用類型重新賦值,也不會導(dǎo)致出現(xiàn) bug 或難以理解。
// bad var a = 1; var b = 2; // good const a = 1; const b = 2;
-
2.2 如果你一定需要可變動的引用,使用
let
替代var
。為什么?因為
let
是塊級作用域,而var
是函數(shù)作用域。// bad var count = 1; if(true){ count += 1; } // good, use the let let count = 1; if(true){ count += 1; }
-
2.3 注意
let
和const
都是塊級作用域。{ let a = 1; const b = 1; } console.log(a);//ReferenceError console.log(b);//ReferenceError
對象
-
3.1 使用字面值創(chuàng)建對象。
// bad const item = new Object(); // good const item = {};
-
3.2 如果你的代碼在瀏覽器環(huán)境下執(zhí)行,別使用 保留字 作為鍵值。但是在ES6模塊或服務(wù)器端使用則沒有問題。
// bad const person = { default: { name: 'peter' }, private: true } // good const person = { defaults: { name: 'peter' }, hidden: true }
-
3.3 使用同義字替換需要使用的保留字。
// bad const person = { class: 'info' } // bad const person = { kclass: 'info' } // good const person = { type: 'info' }
-
3.4 創(chuàng)建有動態(tài)屬性名的對象時,使用可被計算的屬性名稱。
為什么?因為這樣讓你在一個地方定義所有的對象屬性。
function getKey(k){ return `a key named ${k}`; } // bad const obj = { id: 5, name: 'peter' } obj[getKey['enabled']] = true; // good const obj = { id: 5, name: 'peter', [getKey['enabled']]: true; }
-
3.5 使用對象方法的簡寫。
// bad const atom = { value: 1, addValue: function(value){ return atom.value + value; } } // good const atom = { value: 1, addValue(value){ return atom.value + value; } }
-
3.6 使用對象屬性值的簡寫。
const name = 'peter'; // bad const obj = { name: name } // good const obj = { name }
-
3.7 在對象屬性聲明前把簡寫的屬性分組。
const name = 'name'; const age = 'age'; // bad const obj = { name, sex: '男', age, height: '170' } // good const obj = { name, age, sex: '男', height: '170' }
數(shù)組
-
4.1 使用字面值創(chuàng)建數(shù)組。
// bad const items = new Array(); // good const items = [];
-
4.2 向數(shù)組添加元素時使用 Array#push 替代直接賦值。
const names = []; // bad names[0] = 'peter'; // good names.push('peter');
-
4.3 使用拓展運算符
...
復(fù)制數(shù)組。const items = ['xiaoxin', 'xiaoqiang', 'xiaowanzi']; // bad const itemsCopy = []; for(let i = 0; i < items.length; i++){ itemsCopy[i] = items[i]; } // good const itemsCopy = [...items];
解構(gòu)
-
5.1 使用解構(gòu)存取和使用多屬性對象。
為什么?因為解構(gòu)能減少臨時引用屬性。
// bad function getFullName(user){ const fileName = 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 對數(shù)組使用解構(gòu)賦值。
cosnt arr = [1,2,3,4]; // bad const first = arr[0]; const second = arr[1]; //good const [first, second] = arr;
Strings
-
6.1 字符串使用單引號
''
。// bad const name = "peter"; // good const name = 'peter';
-
6.2 字符串超過80個字節(jié)使用字符串連接號連接。
// bad const info = 'American colleges and universities awarded about one million seven hundred thousand bachelor\'s degrees in the school year ending in twenty ten.'; // good const info = 'American colleges and universities awarded about one million seven hundred thousand bachelor\'s ' + 'degrees in the school year ending in twenty ten.'
-
6.3 程序化生成字符串時,使用模板字符串替代字符串連接。
// bad function sayHi(name){ return 'How are you, ' + name + '?'; } // good function sayHi(name){ return `How are you ${name}?` }
函數(shù)
-
7.1 使用函數(shù)聲明代替函數(shù)表達(dá)式。
為什么?因為函數(shù)聲明是可命名的,所以他們在調(diào)用棧中更容易被識別。此外,函數(shù)聲明會把整個函數(shù)提升,而函數(shù)表達(dá)式只會把函數(shù)的引用變量名提升。
// bad const foo = function(){ } // good function foo(){ }
-
7.2 函數(shù)表達(dá)式:
//立即調(diào)用的函數(shù)表達(dá)式 (() => { console.log('Welcome to my home!'); })()
7.3 永遠(yuǎn)不要在一個非函數(shù)代碼塊(
if
,while
等)中聲明一個函數(shù),把那個函數(shù)賦給一個變量。瀏覽器允許你這么做,但它們的解析表現(xiàn)不一致。-
7.4 直接給函數(shù)的參數(shù)指定默認(rèn)值,不要使用一個變化的函數(shù)參數(shù)。
// bad function handleThings(opts){ opts = opts || {}; } // still bad function handleThings(opt){ if(opts === void 0){ opts = {}; } } // good function handleThings(opts = {}){ }
箭頭函數(shù)
-
8.1 當(dāng)你必須使用函數(shù)表達(dá)式(或傳遞一個匿名函數(shù))時,使用箭頭函數(shù)符號。
為什么?因為箭頭函數(shù)創(chuàng)造了新的
this
執(zhí)行環(huán)境,通常情況下都能滿足你的需求,而且這樣的寫法更為簡潔。// bad [1, 2, 3].map(function (x) { return x * x; }) // good [1, 2, 3].map(x => { return x * x; })
-
8.2 如果一個函數(shù)適合用一行寫出并且只有一個參數(shù),那就把花括號、圓括號和
return
都省略掉。如果不是,那就不要省略。// good [1, 2, 3].map(x => x * x); // good [1, 2, 3].map((total, x) => { return total + x; })
構(gòu)造函數(shù)
-
9.1 總是使用 class 。避免直接操作 prototype 。
// 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
繼承。為什么?因為
extends
是一個內(nèi)建的原型繼承方法并且不會破壞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 來幫助鏈?zhǔn)秸{(diào)用。
// 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()}`; } }
模塊
-
10.1 總是使用(
import
/export
)而不是其他非標(biāo)準(zhǔn)模塊系統(tǒng)。你可以編譯為你喜歡的模塊系統(tǒng)。// bad const AirbnbStyleGuide = require('./AirbnbStyleGuide'); module.exports = AirbnbStyleGuide.es6; // ok import AirbnbStyleGuide from './AirbnbStyleGuide'; export default AirbnbStyleGuide.es6; // best import { es6 } from './AirbnbStyleGuide'; export default es6;
-
10.2 不要使用通配符 import。
為什么?這樣能確保你只有一個默認(rèn)的 export。
// bad import * as AirbnbStyleGuide from './AirbnbStyleGuide'; // good import AirbnbStyleGuide from './AirbnbStyleGuide';
-
10.3 不要從 import 中直接 export。
// bad // filename es6.js export { es6 as default } from './airbnbStyleGuide'; // good // filename es6.js import { es6 } from './AirbnbStyleGuide'; export default es6;
屬性
-
11.1 使用
.
來訪問對象的屬性。const student = { name: 'peter', age: 27 } // bad const person = student['name']; // good const person = student.name;
-
11.2 當(dāng)通過變量訪問屬性時使用中括號
[]
.const student = { name: 'peter', age: 27 } function getName(name){ return student[name]; } const name = getName('name');
變量
-
12.1 一直使用 const 來聲明變量,如果不這樣就會產(chǎn)生全局變量。
// bad name = 'peter'; // good const name = 'peter';
-
12.2 使用 const 聲明每一個變量。
// bad const name = 'peter', age = 27; // good const name = 'peter'; const age = 27;
-
12.3 在你需要的地方給變量賦值,但請他它們放在一個合理的位置。
// bad function(hasName) { const name = getName(); if (!hasName) { return false; } this.setFirstName(name); return true; } // good function(hasName) { if (!hasName) { return false; } const name = getName(); this.setFirstName(name); return true; }
比較運算符 & 等號
13.1 優(yōu)先使用
===
和!==
而不是==
和!=
。-
13.2 使用簡寫。
// bad if (name !== '') { } // good if (name) { } // bad if (name.length > 0) { } // good if (name.length) { }
逗號
-
14.1 行首逗號,不需要。
// 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', };
-
14.2 行尾逗號,需要。
為什么? 這會讓
git diff
更干凈。另外,像babel
這樣的轉(zhuǎn)譯器會移除結(jié)尾多于的逗號,也就是說你不必?fù)?dān)心老舊瀏覽器的結(jié)尾逗號問題。// bad const student = { name: 'peter', age: 27 } // good const student = { name: 'peter', age: 27, }
分號
-
15.1 使用分號
// bad (function() { const name = 'Skywalker' return name })() // good (() => { const name = 'Skywalker'; return name; })(); // good (防止函數(shù)在兩個 IIFE 合并時被當(dāng)成一個參數(shù)) ;(() => { const name = 'Skywalker'; return name; })();
類型轉(zhuǎn)換
-
16.1 在語句開始時執(zhí)行類型轉(zhuǎn)換。
// => this.reviewScore = 9; // bad const totalScore = this.reviewScore + ''; // good const totalScore = String(this.reviewScore);
-
16.2 字符串
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);
-
16.3 對數(shù)字使用
parsetInt
轉(zhuǎn)換,病帶上類型轉(zhuǎn)換的基數(shù)。// good /** * 使用 parseInt 導(dǎo)致我的程序變慢, * 改成使用位操作轉(zhuǎn)換數(shù)字快多了。 */ const val = inputValue >> 0;
-
16.4 布爾
const age = 0; // bad const hasAge = new Boolean(age); // good const hasAge = Boolean(age); // good const hasAge = !!age;
命名規(guī)則
-
17.1 避免單字母命名。命名應(yīng)具備描述性。
// bad function q() { // ...stuff... } // good function query() { // ..stuff.. }
-
17.2 使用駝峰式命名對象、函數(shù)和實例。
// bad const OBJEcttsssss = {}; const this_is_my_object = {}; function c() {} // good const thisIsMyObject = {}; function thisIsMyFunction() {}
-
17.3 使用帕斯卡式命名構(gòu)造函數(shù)或類。
// 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', });
-
17.4 使用下劃線 _ 開頭命名私有屬性。
// bad this.__firstName__ = 'Panda'; this.firstName_ = 'Panda'; // good this._firstName = 'Panda';
-
17.5 別保存 this 的引用。使用箭頭函數(shù)或 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); }; }
-
17.6 如果你的文件只輸出一個類,那你的文件名必須和類名完全保持一致。
// 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';
-
17.7 當(dāng)你導(dǎo)出默認(rèn)的函數(shù)時使用駝峰式命名。你的文件名必須和函數(shù)名完全保持一致。
function makeStyleGuide() { } export default makeStyleGuide;
-
17.8 當(dāng)你導(dǎo)出單例、函數(shù)庫、空對象時使用帕斯卡式命名。
const AirbnbStyleGuide = { es6: { } }; export default AirbnbStyleGuide;