- 不使用分號(hào)
- 使用分號(hào)
為什么? 當(dāng) JavaScript 遇到?jīng)]有分號(hào)的換行符時(shí)施籍,它使用一組稱(chēng)為自動(dòng)分號(hào)插入的規(guī)則來(lái)確定是否應(yīng)該將換行符視為語(yǔ)句的結(jié)尾,并且(顧名思義)如果被這樣認(rèn)為的話,在換行符前面自動(dòng)插入一個(gè)分號(hào)。ASI(自動(dòng)分號(hào)插入)包含了一些稀奇古怪的的行為承边,不過(guò),如果 JavaScript 錯(cuò)誤地解釋了你的換行符石挂,你的代碼將會(huì)被中斷執(zhí)行。隨著新功能成為 JavaScript 的一部分险污,這些規(guī)則將變得更加復(fù)雜痹愚。明確地結(jié)束你的語(yǔ)句并配置你的 linter 來(lái)捕獲缺少的分號(hào),將有助于防止遇到問(wèn)題
不使用逗號(hào)結(jié)尾
使用逗號(hào)結(jié)尾
使用let蛔糯,const拯腮,摒棄var
const a = [1, 2], const b = a, b[0] = 9, a = ?, b = ?
- 使用字面量創(chuàng)建Object和Array
// bad
const obj = new Object(), const arr = new Array()
// good
const obj = {1, 2, 3}, const arr = [7, 8, 9]
- {}前后要空格
{ 1, 2, 3 }
- []前后無(wú)需空格
[1, 2, 3]
- 注釋符號(hào)后面要空格
// 注釋
- 逗號(hào)之后要空格
const a = [1, 2, 3]
- 冒號(hào)之后要空格
const obj = { abc: 123 }
- 使用對(duì)象方法速記語(yǔ)法
// bad
const atom = {
value: 1,
addValue: function (value) {
return atom.value + value;
},
}
// good
const atom = {
value: 1,
addValue(value) {
return atom.value + value;
},
}
- 使用表達(dá)式創(chuàng)建funtion
// 為什么? 函數(shù)聲明很容易被提升(Hoisting)蚁飒,你可以在函數(shù)被定義之前引用該函數(shù)动壤。這對(duì)可讀性和可維護(hù)性來(lái)說(shuō)都是不利的。
// bad
function fn () {}
// good
const fn = () => {}
- 使用對(duì)象屬性速記語(yǔ)法
// bad
const obj = { abc: abc }
// good
const obj = { abc }
- 只用引號(hào)引無(wú)效標(biāo)識(shí)符的屬性
// bad
const bad = {
'foo': 3,
'bar': 4,
'data-blah': 5,
}
// good
const good = {
foo: 3,
bar: 4,
'data-blah': 5,
}
- 使用展開(kāi)符…復(fù)制數(shù)組
// bad
const len = items.length
const itemsCopy = []
let i
for (i = 0; i < len; i += 1) {
itemsCopy[i] = items[i]
}
// good
const itemsCopy = [...items]
- 使用展開(kāi)操作符 ... 代替 Array.from
const foo = document.querySelectorAll('.foo');
// good
const nodes = Array.from(foo);
// best
const nodes = [...foo];
- 在數(shù)組方法回調(diào)中使用 return 語(yǔ)句淮逻。如果函數(shù)體由一個(gè)返回?zé)o副作用的表達(dá)式的單個(gè)語(yǔ)句組成琼懊,那么可以省略返回值
// 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
})
- 當(dāng)訪問(wèn)和使用對(duì)象的多個(gè)屬性時(shí),請(qǐng)使用對(duì)象解構(gòu)
// 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}`
}
- 使用數(shù)組解構(gòu)
const arr = [1, 2, 3, 4]
// bad
const first = arr[0]
const second = arr[1]
// good
const [first, second] = arr
- 字符串使用單引號(hào) ''
// bad
const name = "Capt. Janeway"
// bad - 模板字面量應(yīng)該包含插值或換行符
const name = `Capt. Janeway`
// good
const name = 'Capt. Janeway'
- 以編程方式構(gòu)建字符串時(shí)爬早,請(qǐng)使用模板字符串而不是字符串連接
// 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}?`
}
- 不要使用 arguments哼丈,可以選擇 rest 語(yǔ)法 ... 替代
//為什么?使用 ... 能明確你要傳入的參數(shù)筛严。另外 rest(剩余)參數(shù)是一個(gè)真正的數(shù)組醉旦,而 arguments 是一個(gè)類(lèi)數(shù)組(Array-like)。
// bad
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join('');
}
// good
function concatenateAll(...args) {
return args.join('');
}
- 使用默認(rèn)參數(shù)語(yǔ)法,而不要使用一個(gè)變化的函數(shù)參數(shù)
// bad
function handleThings(opts) {
opts = opts || {};
// 如果opts的值就是false怎么辦车胡?按上面的寫(xiě)法檬输,它永遠(yuǎn)等于{}了,也就是true
// ...
}
// good
function handleThings(opts = {}) {
// ...
}
- 不要改變參數(shù)
// 為什么匈棘?因?yàn)閷?duì)象是引用類(lèi)型丧慈,操作作為參數(shù)傳入的對(duì)象,可能會(huì)在調(diào)用原始對(duì)象時(shí)造成不必要的變量副作用羹饰。
// bad
function f1(obj) {
obj.key = 1
}
// good
function f2(obj) {
const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1
}
- 參數(shù)不要重新賦值
// 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) {
// ...
}
- 如果你的函數(shù)只有一個(gè)參數(shù)并且不使用大括號(hào)伊滋,則可以省略參數(shù)括號(hào)。否則队秩,為了清晰和一致性笑旺,總是給參數(shù)加上括號(hào)
// 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 don’t want it to take up space on the .map line!`
))
// 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
})
- 一個(gè)地方只在一個(gè)路徑中 import(導(dǎo)入)
// bad
import foo from 'foo'
// … 其他一些 imports … //
import { named1, named2 } from 'foo'
// good
import foo, { named1, named2 } from 'foo'
// good
import foo, {
named1,
named2,
} from 'foo'
- 將所有 import 導(dǎo)入放在非導(dǎo)入語(yǔ)句的上面
// bad
import foo from 'foo'
foo.init()
import bar from 'bar'
// good
import foo from 'foo'
import bar from 'bar'
foo.init()
- 不要使用 iterators(迭代器) 。請(qǐng)使用高階函數(shù)馍资,例如 map() 和 reduce() 等?筒主,而不是像 for-in 或 for-of 這樣的循環(huán)
// 為什么? 這是強(qiáng)制執(zhí)行我們不變性的規(guī)則鸟蟹。 處理返回值的純函數(shù)比副作用更容易推理乌妙。
// 使用 map() / every() / filter() / find() / findIndex() / reduce() / some() / … 來(lái)迭代數(shù)組, 使用 Object.keys() / Object.values() / Object.entries() 來(lái)生成數(shù)組,以便可以迭代對(duì)象建钥。
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
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
const increasedByOne = numbers.map(num => num + 1)
- 使用 const 或 let聲明每個(gè)變量
const items = getItems()
const goSportsTeam = true
const dragonball = 'z'
- 避免使用一元遞增和遞減運(yùn)算符(++, --)
let a = 1
// bad
a++
// good
a += 1
盡量使用 === 和 !== 而非 == 和 !=
在 case 和 default 子句中藤韵,使用大括號(hào)來(lái)創(chuàng)建包含詞法聲明的語(yǔ)句塊
// 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 {}
}
}
- 三元表達(dá)式不應(yīng)該嵌套,通常寫(xiě)成單行表達(dá)式
// bad
const foo = maybe1 > maybe2
? "bar"
: value1 > value2 ? "baz" : null
// 拆分成2個(gè)分離的三元表達(dá)式
const maybeNull = value1 > value2 ? 'baz' : null
// better
const foo = maybe1 > maybe2
? 'bar'
: maybeNull
// best
const foo = maybe1 > maybe2 ? 'bar' : maybeNull
- 避免不必要的三元表達(dá)式語(yǔ)句
// 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
- 當(dāng)運(yùn)算符混合在一個(gè)語(yǔ)句中時(shí)熊经,請(qǐng)將其放在括號(hào)內(nèi)泽艘。混合算術(shù)運(yùn)算符時(shí)镐依,不要將 和 % 與 + 匹涮, -,*槐壳,/ 混合在一起
// bad
const foo = a && b < 0 || c > 0 || d + 1 === 0
// bad
const bar = a ** b - 5 % d
// bad
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
- 如果一個(gè) if 塊總是執(zhí)行一個(gè) return 語(yǔ)句然低,后面的 else 塊是不必要的。在 else if 塊中的 return务唐,可以分成多個(gè) if 塊來(lái) return
// 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
}
}
- 在大括號(hào)前放置 1 個(gè)空格
// 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',
})
- 在控制語(yǔ)句(if雳攘、while 等)的小括號(hào)前放一個(gè)空格。在函數(shù)調(diào)用及聲明中枫笛,不在函數(shù)的參數(shù)列表前加空格
// bad
if(isJedi) {
fight ()
}
// good
if (isJedi) {
fight()
}
// bad
function fight () {
console.log ('Swooosh!')
}
// good
function fight() {
console.log('Swooosh!')
}
- 使用空格把運(yùn)算符隔開(kāi)
// bad
const x=y+5
// good
const x = y + 5
在文件末尾插入一個(gè)空行
在聲明語(yǔ)句的開(kāi)始處就執(zhí)行強(qiáng)制類(lèi)型轉(zhuǎn)換
創(chuàng)建字符串
// => this.reviewScore = 9
// bad
const totalScore = new String(this.reviewScore) // typeof totalScore 是 "object" 而不是 "string"
// bad
const totalScore = this.reviewScore + '' // 調(diào)用 this.reviewScore.valueOf()
// bad
const totalScore = this.reviewScore.toString() // 不能保證返回一個(gè)字符串
// good
const totalScore = String(this.reviewScore)
- 數(shù)字: 使用 Number 進(jìn)行轉(zhuǎn)換来农,而 parseInt 則始終以基數(shù)解析字串
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)
- 創(chuàng)建布爾值
const age = 0
// bad
const hasAge = new Boolean(age)
// good
const hasAge = Boolean(age)
// best
const hasAge = !!age
避免使用單字母名稱(chēng)。使你的命名具有描述性
當(dāng)命名對(duì)象崇堰,函數(shù)和實(shí)例時(shí)使用駝峰式命名
當(dāng)命名構(gòu)造函數(shù)或類(lèi)的時(shí)候使用單詞首字母大寫(xiě)方式命名
將綁定數(shù)據(jù)到事件時(shí) (不論是 DOM 事件還是其他像Backbone一類(lèi)的事件), 傳遞 hash 而不是原始值沃于。 這將允許后續(xù)的貢獻(xiàn)者不用查找和更新事件的每一個(gè)處理程序就可以給事件添加更多的數(shù)據(jù)
// 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
})
- Number.isNaN 代替全局 isNaN
// 為什么涩咖?全局的 isNaN 方法會(huì)將非數(shù)字轉(zhuǎn)換為數(shù)字, 任何被轉(zhuǎn)換為 NaN 的東西都會(huì)返回 true
// bad
isNaN('1.2') // false
isNaN('1.2.3') // true
// good
Number.isNaN('1.2.3') // false
Number.isNaN(Number('1.2.3')) // true
- Number.isFinite 代替全局 isFinite
// 為什么?全局的 isFinite 方法會(huì)將非數(shù)字轉(zhuǎn)換為數(shù)字, 任何被轉(zhuǎn)換為有限大的數(shù)字都會(huì)返回 true
// bad
isFinite('2e3') // true
// good
Number.isFinite('2e3') // false
Number.isFinite(parseInt('2e3', 10)) // true