編寫現代 JavaScript 代碼

原文做者:Sébastien Castieljavascript

原文連接:Writing modern JavaScript codehtml

說點什麼:這是一篇很樸素的文章,講的道理都懂,但實際上,在工做中遇到相似的情形卻未必如此,編寫可維護,可閱讀,更安全的代碼是咱們應有的責任。前端

是否是還認爲 JavaScript 是一門用於在光標懸浮時改變頁面元素的語言?這些日子已經不復存在,每一種語言都在隨着時間推移而發展,咱們使用語言的方式一樣也在發展。看一下你一兩年前寫的代碼:會感到羞愧嗎?若是是的話,這篇文章應該很適合你。java

這裏會列出一些所謂的最佳實踐,目的是讓你的 JavaScript 代碼更容易編寫,閱讀和維護。react

使用可格式化代碼的 linter

第一個建議是使用 linter 工具,能夠幫助你檢查在不一樣文件是否遵照一致的規則,尤爲是當不一樣開發人員在同一個項目上工做:縮進,括號中的空格,替換 ===== ...webpack

但更重要的是,儘量使用 linter 工具自動修復代碼。ESLint 就作得很好(帶有 --fix 選項),並且與全部主流 IDE 完美集成,能夠在保存時自動修復文件。git

還可使用 Prettier,不過這款工具更注重格式化而不是靜態檢查,但處理後的結果基本相同。es6

下一步將介紹與 linter 工具一塊兒使用的規則:github

爲你的 linter 定製現代化的規則

若是不知道你的代碼須要什麼樣的規則,能夠參考:StandardJS。這是一個很是嚴格的 linter,沒法修改配置,但裏面的每一條規則已經愈來愈多地被社區接納。好比:web

  • 使用 2 個空格縮進(我曾經使用 4 個空格,但實際使用起來 2 個空格很不錯)

  • 不使用分號(一開始可能會以爲奇怪,但幾天後就再也回不去了)

  • 在關鍵字(如 if)和花括號使用空格,在括號不使用空格

  • 等等

StandardJS 是一個獨立的 Node 模塊,能夠進行 lint 和修復代碼,但若是要在現有的大型項目中使用,而且想要停用一些規則(由於有些地方可能須要做大量修改),還可使用 ESLint 預約配置。好比,我就停用了規則 no-mixed-operatorsimport / no-webpack-loader-syntax

使用 ES2015+ 的新特性

若是你在使用 JavaScript 開發,根本沒辦法不據說 ES2015 +(或 ES6,ES7 ...)的特性。有的已是我離不開的:

  • 箭頭函數:對於函數式編程,好比寫 x => x * 2 這樣的函數很是有用(見下一點)

  • 類:中止使用原型函數,使用類更酷炫(但不要濫用,JavaScript 比任何面向對象的語言好多了)

  • 對數組和對象的操做:

function doSomething() {
  const a = doSomethingElse()
  const b = doSomethingWithA(a)
  const otherResults = { c: '?', d: '?' }
  return { a, b, ...otherResults } // equivalent to { a: a, b: b }
}
const { a, c, ...rest } = doSomething() // Also works with arrays!
// `rest` looks like { b: ..., d: '?' }
  • 使用 async/await 編寫更簡單的異步處理:

// Please try to write the same code with classic promises ;)
async function doSomething() {
  const a = await getValueForA()
  const b = await getValueForBFromA(a)
  const [c, d] = await Promise.all([
    // parallel execution
    getValueForC(), getValueForDFromB(b)
  ])
  const total = await calculateTotal(a, b, c, d)
  return total / 1000
}

想知道如何使用這些特性呢?個人另外一篇文章能給一些建議。(順便說一下,使用最新版本的 Node.js,可能再也不須要 Babel 就能使用這些新特性)

使用函數式編程

函數式編程最近很熱門,取得很多成就,並且不只僅是在 JavaScript 中。爲何呢?函數式編程能使代碼更具可預測性,肯定性,更安全,一旦習慣這種方式,代碼會更容易維護。這裏有一些簡單的建議:

首先,中止使用 for 循環,在大多數(多是全部?)狀況下根本不須要。例如:

const arr = [{ name: 'first', value: 13 }, { name: 'second', value: 7 }]

// Instead of:
const res = {}
for (let i = 0; i < arr.length; i++) {
  const calculatedValue = arr[i].value * 10
  if (calculatedValue > 100) {
    res[arr[i].name] = calculatedValue
  }
}

// Prefer:
const res = arr
  .map(elem => ({ name: elem.name, calculatedValue: elem.value * 10 }))
  .filter(elem => elem.calculatedValue > 100)
  .reduce((acc, elem) => ({
    [elem.name]: elem.calculatedValue,
    ...acc
  }), {})

好吧,這其實是一個很是極端的例子,對於不習慣函數式編程的人而言,可能看起來更加複雜。但咱們能夠稍微簡化一下:

const enrichElementWithCalculatedValue =
  elem => ({ name: elem.name, calculatedValue: elem.value * 10 })
const filterElementsByValue = value =>
  elem => elem.calculatedValue > value
const aggregateElementInObject = (acc, elem) => ({
  [elem.name]: elem.calculatedValue,
  ...acc
})
const res = arr
  .map(enrichElementWithCalculatedValue)
  .filter(filterElementsByValue(100))
  .reduce(aggregateElementInObject, {})

在這裏,咱們定義了三個函數,其功能基本上與其名字一致。第二個建議:建立局部函數(即便是在已經存在的函數中)來講明代碼的功能,不須要使用註釋。

注意,三個局部函數不修改它們的執行上下文。沒有外部變量被修改,沒有其餘服務被調用...在函數式編程中,它們被稱爲純函數。純函數具備很大的優點:

  • 很容易測試,由於從給定參數只有一個可能的結果,無論被調用了多少次;

  • 不管應用狀態如何,都能保證相同的結果;

  • 應用狀態在函數調用以前和以後保持不變。

因此個人第三個建議是:儘量地使用純函數。

其餘的一些建議

  • 習慣於使用異步代碼,並多使用 promise,看看 RxJS 的 observales(有一個很棒的教程關於從函數式編程到響應式編程

  • 寫測試!這應該是很明顯的,可是據我所知不少項目都有未經測試的代碼,儘管測試 JavaScript(前端或後端)並不困難。

  • 使用最新的語言特性:好比不要再寫 arr.indexOf(elem) !== -1,而應該寫成 arr.includes(elem)

  • 大量閱讀技術文章:JavaScript subreddit 是瞭解目前社區最酷作法的一個很好的來源。

總而言之,最好的建議就是:老是重構你的代碼。好比改進你一年前寫過的模塊?藉此機會,用 const 取代 var,使用箭頭函數或 async/await 簡化代碼......和你喜歡的代碼工做一件很愉悅的事。

相關文章
相關標籤/搜索