JS 語言規(guī)范

2021-11-30 14:14 更新

語言規(guī)范

JavaScript 是一種客戶端腳本語言,這里列出了編寫 JavaScript 時需要遵守的規(guī)則。

類型

  • 基本類型

    • 字符串
    • 數(shù)值
    • 布爾類型
    • null
    • undefined
    const foo = 1
    let bar = foo
    
    bar = 9
    
    console.log(foo, bar) // 1, 9
    
  • 復(fù)雜類型

    • object
    • array
    • function
    const foo = [1, 2, 3]
    const bar = foo
    
    bar[0] = 9
    
    console.log(foo[0], bar[0]) // 9, 9
    

引用

constlet 都是塊級作用域,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
    }
    

數(shù)組

  • 請使用字面量值創(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
    })
    

解構(gòu)賦值

  • 當(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ù)聲明,而不是函數(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 模塊語法 importexport

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

變量聲明

  • 聲明變量時,請使用 constlet 關(guān)鍵字,如果沒有寫關(guān)鍵字,變量就會暴露在全局上下文中,這樣很可能會和現(xiàn)有變量沖突,另外,也很難明確該變量的作用域是什么。這里推薦使用 const 來聲明變量,我們需要避免全局命名空間的污染。

    // bad
    demo = new Demo()
    
    // good
    const demo = new Demo()
    
  • 將所有的 constlet 分組

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

Hoisting

  • var 存在變量提升的情況,即 var 聲明會被提升至該作用域的頂部,但是他們的賦值并不會。而 constlet 并不存在這種情況,他們被賦予了 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'
    })();
    

標(biāo)準(zhǔn)特性

為了代碼的可移植性和兼容性,我們應(yīng)該最大化的使用標(biāo)準(zhǔn)方法,例如優(yōu)先使用 string.charAt(3) 而不是 string[3]

eval()

由于 eval 方法比較 evil,所以我們約定禁止使用該方法

with() {}

由于 with 方法會產(chǎn)生神奇的作用域,所以我們也是禁止使用該方法的

for-in 循環(huán)

推薦使用 for in 語法,但是在對對象進(jìn)行操作時,容易忘了檢測 hasOwnProperty(key),所以我們啟用了 ESLintguard-for-in 選項(xiàng)

對數(shù)組進(jìn)行 for in 的時候,順序是不固定的

修改內(nèi)置對象的原型

不要修改內(nèi)置對象,如 ObjectArray


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號