JavaScript 是一種客戶端腳本語言,這里列出了編寫 JavaScript 時需要遵守的規(guī)則。
基本類型
const foo = 1
let bar = foo
bar = 9
console.log(foo, bar) // 1, 9
復(fù)雜類型
const foo = [1, 2, 3]
const bar = foo
bar[0] = 9
console.log(foo[0], bar[0]) // 9, 9
const
和 let
都是塊級作用域,var
是函數(shù)級作用域
對所有引用都使用 const
,不要使用 var
// bad
var a = 1
var b = 2
// good
const a = 1
const b = 2
如果引用是可變動的,則使用 let
// bad
var count = 1
if (count < 10) {
count += 1
}
// good
let count = 1
if (count < 10) {
count += 1
}
請使用字面量值創(chuàng)建對象
// bad
const a = new Object{}
// good
const a = {}
別使用保留字作為對象的鍵值,這樣在 IE8 下不會運(yùn)行
// bad
const a = {
default: {}, // default 是保留字
common: {}
}
// good
const a = {
defaults: {},
common: {}
}
請使用對象方法的簡寫方式
// bad
const item = {
value: 1,
addValue: function (val) {
return item.value + val
}
}
// good
const item = {
value: 1,
addValue(val) {
return item.value + val
}
}
請使用對象屬性值的簡寫方式
const job = 'FrontEnd'
// bad
const item = {
job: job
}
// good
const item = {
job
}
對象屬性值的簡寫方式要和聲明式的方式分組
const job = 'FrontEnd'
const department = 'JDC'
// bad
const item = {
sex: 'male',
job,
age: 25,
department
}
// good
const item = {
job,
department,
sex: 'male',
age: 25
}
請使用字面量值創(chuàng)建數(shù)組
// bad
const items = new Array()
// good
const items = []
向數(shù)組中添加元素時,請使用 push
方法
const items = []
// bad
items[items.length] = 'test'
// good
items.push('test')
使用拓展運(yùn)算符 ...
復(fù)制數(shù)組
// bad
const items = []
const itemsCopy = []
const len = items.length
let i
// bad
for (i = 0; i < len; i++) {
itemsCopy[i] = items[i]
}
// good
itemsCopy = [...items]
使用數(shù)組的 map
等方法時,請使用 return
聲明,如果是單一聲明語句的情況,可省略 return
// bad
[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] = flatten
})
// 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
})
當(dāng)需要使用對象的多個屬性時,請使用解構(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}`
}
// better
function getFullName ({ firstName, lastName }) {
return `${firstName} ${lastName}`
}
當(dāng)需要使用數(shù)組的多個值時,請同樣使用解構(gòu)賦值
const arr = [1, 2, 3, 4]
// bad
const first = arr[0]
const second = arr[1]
// good
const [first, second] = arr
函數(shù)需要回傳多個值時,請使用對象的解構(gòu),而不是數(shù)組的解構(gòu)
// bad
function doSomething () {
return [top, right, bottom, left]
}
// 如果是數(shù)組解構(gòu),那么在調(diào)用時就需要考慮數(shù)據(jù)的順序
const [top, xx, xxx, left] = doSomething()
// good
function doSomething () {
return { top, right, bottom, left }
}
// 此時不需要考慮數(shù)據(jù)的順序
const { top, left } = doSomething()
字符串統(tǒng)一使用單引號的形式 ''
// bad
const department = "JDC"
// good
const department = 'JDC'
字符串太長的時候,請不要使用字符串連接符換行 \
,而是使用 +
const str = '凹凸實(shí)驗(yàn)室 凹凸實(shí)驗(yàn)室 凹凸實(shí)驗(yàn)室' +
'凹凸實(shí)驗(yàn)室 凹凸實(shí)驗(yàn)室 凹凸實(shí)驗(yàn)室' +
'凹凸實(shí)驗(yàn)室 凹凸實(shí)驗(yàn)室'
程序化生成字符串時,請使用模板字符串
const test = 'test'
// bad
const str = ['a', 'b', test].join()
// bad
const str = 'a' + 'b' + test
// good
const str = `ab${test}`
請使用函數(shù)聲明,而不是函數(shù)表達(dá)式
// bad
const foo = function () {
// do something
}
// good
function foo () {
// do something
}
不要在非函數(shù)代碼塊中聲明函數(shù)
// bad
if (isUse) {
function test () {
// do something
}
}
// good
let test
if (isUse) {
test = () => {
// do something
}
}
不要使用 arguments
,可以選擇使用 ...
arguments
只是一個類數(shù)組,而...
是一個真正的數(shù)組
// bad
function test () {
const args = Array.prototype.slice.call(arguments)
return args.join('')
}
// good
function test (...args) {
return args.join('')
}
不要更改函數(shù)參數(shù)的值
// bad
function test (opts) {
opts = opts || {}
}
// good
function test (opts = {}) {
// ...
}
使用 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
}
}
使用標(biāo)準(zhǔn)的 ES6 模塊語法 import
和 export
// bad
const util = require('./util')
module.exports = util
// good
import Util from './util'
export default Util
// better
import { Util } from './util'
export default Util
不要使用 import
的通配符 *
,這樣可以確保你只有一個默認(rèn)的 export
// bad
import * as Util from './util'
// good
import Util from './util'
不要使用 iterators
const numbers = [1, 2, 3, 4, 5]
// bad
let sum = 0
for (let num of numbers) {
sum += num
}
// good
let sum = 0
numbers.forEach(num => sum += num)
// better
const sum = numbers.reduce((total, num) => total + num, 0)
使用 .
來訪問對象屬性
const joke = {
name: 'haha',
age: 28
}
// bad
const name = joke['name']
// good
const name = joke.name
聲明變量時,請使用 const
、let
關(guān)鍵字,如果沒有寫關(guān)鍵字,變量就會暴露在全局上下文中,這樣很可能會和現(xiàn)有變量沖突,另外,也很難明確該變量的作用域是什么。這里推薦使用 const
來聲明變量,我們需要避免全局命名空間的污染。
// bad
demo = new Demo()
// good
const demo = new Demo()
將所有的 const
和 let
分組
// bad
let a
const b
let c
const d
let e
// good
const b
const d
let a
let c
let e
1.單行注釋:
兩個斜杠 // 可以創(chuàng)建一個單行注釋,斜杠后面要增加一個空格,緊接著是注釋內(nèi)容。
注釋的縮進(jìn)需要與所注釋的代碼一致,且要位于被注釋代碼的上面。
代碼演示如下:
// w3cschool教程測試函數(shù)
function func() {
// 用來存儲定時器函數(shù)標(biāo)識
let flag = null;
}
2.多行注釋:
/*/ 可以創(chuàng)建多行注釋,也就是以 "/" 開始,"*/" 結(jié)束,中間是注釋內(nèi)容。
既然是多行注釋,自然被注釋的內(nèi)容是可以換行的。
盡量使用單行注釋替代多行注釋,如果注釋函數(shù),推薦使用多行注釋。
3.函數(shù)的注釋:
函數(shù)是使用最為頻繁的語法結(jié)構(gòu),相對較為復(fù)雜,所以良好的注釋對于理解函數(shù)的功能非常有必要。
注釋格式如下:
/*方法說明
*@method 方法名
*@for 所屬類名
*@param{參數(shù)類型}參數(shù)名 參數(shù)說明
*@return {返回值類型} 返回值說明
*/
可以看到在注釋的開始于結(jié)尾分別是 / 與 /,具體的注釋內(nèi)容前面也帶有一個星號,看起來更加整齊。
看一段簡單的注釋代碼實(shí)例:
/*函數(shù)說明
* @param {string} p1 參數(shù)1的說明
* @param {string} p2 參數(shù)2的說明,比較長
* 那就換行了.
* @param {number=} p3 參數(shù)3的說明(可選)
* @return {Object} 返回值描述
*/
function foo(p1, p2, p3) {
var p3 = p3 || 10;
return {
p1: p1,
p2: p2,
p3: p3
};
}
4.模塊注釋:
模塊注釋格式如下:
/* 模塊說明
* @module 模塊名
*/
/* 類說明
* @class 類名
* @constructor
*/
由于類分為靜態(tài)類與非靜態(tài)類,所以 class 需要與 constructor 或者 static 配合使用。
5.注釋內(nèi)容:
知道為什么需要注釋,那么也就知道注釋應(yīng)該怎么寫。
注釋的目的是告訴閱讀者不宜察覺或者不易獲取到的信息,而不是一目了然的東西。
// 聲明一個變量timer
let timer=null;
var
存在變量提升的情況,即 var
聲明會被提升至該作用域的頂部,但是他們的賦值并不會。而 const
和 let
并不存在這種情況,他們被賦予了 Temporal Dead Zones, TDZ
function example () {
console.log(notDefined) // => throws a ReferenceError
}
function example () {
console.log(declareButNotAssigned) // => undefined
var declaredButNotAssigned = true
}
function example () {
let declaredButNotAssigned
console.log(declaredButNotAssigned) // => undefined
declaredButNotAssigned = true
}
function example () {
console.log(declaredButNotAssigned) // => throws a ReferenceError
console.log(typeof declaredButNotAssigned) // => throws a ReferenceError
const declaredButNotAssigned = true
}
匿名函數(shù)的變量名會提升,但函數(shù)內(nèi)容不會
function example () {
console.log(anonymous) // => undefined
anonymous()
var anonymous = function () {
console.log('test')
}
}
命名的函數(shù)表達(dá)式的變量名會被提升,但函數(shù)名和函數(shù)函數(shù)內(nèi)容并不會
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')
}
}
我們遵循 Standard
的規(guī)范,不使用分號。
關(guān)于應(yīng)不應(yīng)該使用分號的討論有很多,本規(guī)范認(rèn)為非必要的時候,應(yīng)該不使用分號,好的
JS
程序員應(yīng)該清楚場景下是一定要加分號的,相信你也是名好的開發(fā)者。
// bad
const test = 'good';
(function () {
const str = 'hahaha';
})()
// good
const test = 'good'
;(() => {
const str = 'hahaha'
})();
為了代碼的可移植性和兼容性,我們應(yīng)該最大化的使用標(biāo)準(zhǔn)方法,例如優(yōu)先使用 string.charAt(3)
而不是 string[3]
由于 eval
方法比較 evil
,所以我們約定禁止使用該方法
由于 with
方法會產(chǎn)生神奇的作用域,所以我們也是禁止使用該方法的
推薦使用 for in
語法,但是在對對象進(jìn)行操作時,容易忘了檢測 hasOwnProperty(key)
,所以我們啟用了 ESLint
的 guard-for-in
選項(xiàng)
對數(shù)組進(jìn)行
for in
的時候,順序是不固定的
不要修改內(nèi)置對象,如 Object
和 Array
更多建議: