2022 年 6 月 26 日

編碼樣式

我們的程式碼必須盡可能乾淨且易於閱讀。

這實際上就是程式設計的藝術 – 以正確且人類可讀的方式執行複雜的任務。良好的程式碼樣式對此有很大的幫助。

語法

以下是建議規則的秘笈(有關更多詳細資訊,請參閱下方)

現在讓我們詳細討論這些規則和原因。

沒有「你必須」的規則

這裡沒有任何規則是絕對的。這些是樣式偏好,而不是宗教教條。

大括號

在大部分 JavaScript 專案中,大括號會以「埃及」風格撰寫,其中開啟大括號與對應關鍵字位於同一行,而非新的一行。在開啟大括號前也應該有一個空格,如下所示

if (condition) {
  // do this
  // ...and that
  // ...and that
}

單行建構,例如 if (condition) doSomething(),是一個重要的邊界案例。我們應該使用大括號嗎?

以下是有註解的變體,讓您可以自行判斷其可讀性

  1. 😠 初學者有時會這樣做。很糟糕!不需要大括號
    if (n < 0) {alert(`Power ${n} is not supported`);}
  2. 😠 分割到沒有大括號的獨立行。永遠不要這樣做,在新增新行時容易出錯
    if (n < 0)
      alert(`Power ${n} is not supported`);
  3. 😏 沒有大括號的一行,如果很短,是可以接受的
    if (n < 0) alert(`Power ${n} is not supported`);
  4. 😃 最佳變體
    if (n < 0) {
      alert(`Power ${n} is not supported`);
    }

對於非常簡短的程式碼,允許一行,例如 if (cond) return null。但程式碼區塊(最後一個變體)通常更具可讀性。

行長

沒有人喜歡閱讀很長的水平程式碼行。最佳做法是將它們分隔開來。

例如

// backtick quotes ` allow to split the string into multiple lines
let str = `
  ECMA International's TC39 is a group of JavaScript developers,
  implementers, academics, and more, collaborating with the community
  to maintain and evolve the definition of JavaScript.
`;

對於 if 陳述式

if (
  id === 123 &&
  moonPhase === 'Waning Gibbous' &&
  zodiacSign === 'Libra'
) {
  letTheSorceryBegin();
}

最大行長應由團隊層級達成共識。通常為 80 或 120 個字元。

縮排

有兩種縮排

  • 水平縮排:2 或 4 個空格。

    水平縮排使用 2 或 4 個空格或水平標籤符號(按鍵 Tab)來製作。選擇哪一種是一個古老的聖戰。如今空格更為常見。

    空格比標籤符號的一個優點是,空格允許比標籤符號更靈活的縮排設定。

    例如,我們可以將參數與開啟大括號對齊,如下所示

    show(parameters,
         aligned, // 5 spaces padding at the left
         one,
         after,
         another
      ) {
      // ...
    }
  • 垂直縮排:用於將程式碼分割成邏輯區塊的空行。

    即使是一個單一函式,通常也可以分成邏輯區塊。在以下範例中,變數的初始化、主迴圈和傳回結果會垂直分割

    function pow(x, n) {
      let result = 1;
      //              <--
      for (let i = 0; i < n; i++) {
        result *= x;
      }
      //              <--
      return result;
    }

    在有助於讓程式碼更具可讀性的位置插入額外的換行符號。在沒有垂直縮排的情況下,程式碼行數不應超過九行。

分號

每個陳述式後面都應該有分號,即使它有可能被略過。

有些語言中分號真的是可選的,而且很少使用。然而,在 JavaScript 中,有些情況下換行符號不會被解釋為分號,導致程式碼容易出錯。在 程式碼結構 章節中進一步了解這一點。

如果您是一位經驗豐富的 JavaScript 程式設計師,您可以選擇不使用分號的程式碼風格,例如 StandardJS。否則,最好使用分號以避免潛在的陷阱。大多數開發人員都會使用分號。

巢狀層級

請盡量避免巢狀程式碼過於深入。

例如,在迴圈中,有時建議使用 continue 指令以避免額外的巢狀。

例如,不要像這樣新增巢狀 if 條件式

for (let i = 0; i < 10; i++) {
  if (cond) {
    ... // <- one more nesting level
  }
}

我們可以撰寫

for (let i = 0; i < 10; i++) {
  if (!cond) continue;
  ...  // <- no extra nesting level
}

使用 if/elsereturn 可以執行類似操作。

例如,以下兩個建構相同。

選項 1

function pow(x, n) {
  if (n < 0) {
    alert("Negative 'n' not supported");
  } else {
    let result = 1;

    for (let i = 0; i < n; i++) {
      result *= x;
    }

    return result;
  }
}

選項 2

function pow(x, n) {
  if (n < 0) {
    alert("Negative 'n' not supported");
    return;
  }

  let result = 1;

  for (let i = 0; i < n; i++) {
    result *= x;
  }

  return result;
}

第二個選項較易讀取,因為 n < 0 的「特殊情況」會在早期處理。完成檢查後,我們可以繼續執行「主要」程式碼流程,而不需要額外的巢狀。

函式放置

如果您正在撰寫多個「輔助」函式和使用它們的程式碼,則有三個方法可以整理函式。

  1. 在使用它們的程式碼上方宣告函式

    // function declarations
    function createElement() {
      ...
    }
    
    function setHandler(elem) {
      ...
    }
    
    function walkAround() {
      ...
    }
    
    // the code which uses them
    let elem = createElement();
    setHandler(elem);
    walkAround();
  2. 程式碼優先,然後是函式

    // the code which uses the functions
    let elem = createElement();
    setHandler(elem);
    walkAround();
    
    // --- helper functions ---
    function createElement() {
      ...
    }
    
    function setHandler(elem) {
      ...
    }
    
    function walkAround() {
      ...
    }
  3. 混合:在函式首次使用的位置宣告函式。

大多數時候,建議使用第二個變體。

這是因為在閱讀程式碼時,我們首先想要知道它執行什麼動作。如果程式碼優先,則從一開始就變得清晰。然後,我們可能完全不需要閱讀函式,特別是如果函式名稱描述了它們實際執行的動作。

風格指南

風格指南包含有關「如何撰寫」程式碼的一般規則,例如使用哪些引號、縮排多少空格、最大行長度等。許多小事。

當團隊的所有成員使用相同的風格指南時,程式碼看起來會一致,無論是由哪位團隊成員撰寫。

當然,團隊隨時可以撰寫自己的風格指南,但通常沒有必要。有許多現有的指南可供選擇。

一些熱門選擇

如果您是新手開發人員,請從本章開頭的秘笈開始。然後,您可以瀏覽其他樣式指南以獲取更多想法,並決定您最喜歡哪一個。

自動化 Linter

Linter 是可以自動檢查您的程式碼樣式並提出改進建議的工具。

它們的優點在於,樣式檢查還可以找出一些錯誤,例如變數或函式名稱中的錯字。由於此功能,即使您不想堅持使用某一種特定的「程式碼樣式」,也建議使用 Linter。

以下是一些著名的 Linting 工具

  • JSLint – 最早的 Linter 之一。
  • JSHint – 設定比 JSLint 多。
  • ESLint – 可能是最新的。

它們都可以完成這項工作。作者使用 ESLint

大多數 Linter 都與許多流行的編輯器整合:只需在編輯器中啟用外掛程式並設定樣式即可。

例如,對於 ESLint,您應該執行以下操作

  1. 安裝 Node.js
  2. 使用命令 npm install -g eslint 安裝 ESLint(npm 是 JavaScript 套件安裝程式)。
  3. 在 JavaScript 專案的根目錄(包含所有檔案的資料夾)中建立一個名為 .eslintrc 的設定檔。
  4. 安裝/啟用與 ESLint 整合的編輯器外掛程式。大多數編輯器都有。

以下是 .eslintrc 檔案範例

{
  "extends": "eslint:recommended",
  "env": {
    "browser": true,
    "node": true,
    "es6": true
  },
  "rules": {
    "no-console": 0,
    "indent": 2
  }
}

此處的指令 "extends" 表示設定是根據「eslint:recommended」設定集。在那之後,我們指定我們自己的設定。

也可以從網路上下載樣式規則集並延伸它們。請參閱 https://eslint.dev.org.tw/docs/user-guide/getting-started 以取得更多關於安裝的詳細資訊。

此外,某些 IDE 內建 Linting,這很方便,但沒有 ESLint 那麼可自訂。

摘要

本章(和參考的樣式指南)中描述的所有語法規則旨在提高程式碼的可讀性。它們都是有爭議的。

當我們思考撰寫「更好的」程式碼時,我們應該問自己的問題是:「什麼讓程式碼更具可讀性和更容易理解?」以及「什麼可以幫助我們避免錯誤?」這些是選擇和辯論程式碼樣式時要牢記的主要事項。

閱讀流行的樣式指南將使您能夠隨時了解程式碼樣式趨勢和最佳實務的最新想法。

任務

重要性:4

以下程式碼樣式有什麼問題?

function pow(x,n)
{
  let result=1;
  for(let i=0;i<n;i++) {result*=x;}
  return result;
}

let x=prompt("x?",''), n=prompt("n?",'')
if (n<=0)
{
  alert(`Power ${n} is not supported, please enter an integer number greater than zero`);
}
else
{
  alert(pow(x,n))
}

修復它。

您可以注意以下事項

function pow(x,n)  // <- no space between arguments
{  // <- figure bracket on a separate line
  let result=1;   // <- no spaces before or after =
  for(let i=0;i<n;i++) {result*=x;}   // <- no spaces
  // the contents of { ... } should be on a new line
  return result;
}

let x=prompt("x?",''), n=prompt("n?",'') // <-- technically possible,
// but better make it 2 lines, also there's no spaces and missing ;
if (n<=0)  // <- no spaces inside (n <= 0), and should be extra line above it
{   // <- figure bracket on a separate line
  // below - long lines can be split into multiple lines for improved readability
  alert(`Power ${n} is not supported, please enter an integer number greater than zero`);
}
else // <- could write it on a single line like "} else {"
{
  alert(pow(x,n))  // no spaces and missing ;
}

已修復的變體

function pow(x, n) {
  let result = 1;

  for (let i = 0; i < n; i++) {
    result *= x;
  }

  return result;
}

let x = prompt("x?", "");
let n = prompt("n?", "");

if (n <= 0) {
  alert(`Power ${n} is not supported,
    please enter an integer number greater than zero`);
} else {
  alert( pow(x, n) );
}
教學課程地圖

留言

在留言前請先閱讀…
  • 如果您有改善建議,請提交 GitHub 問題或提交拉取請求,而不要留言。
  • 如果您無法理解文章中的某些內容,請詳細說明。
  • 若要插入少數幾個字的程式碼,請使用 <code> 標籤,若要插入多行,請將其包覆在 <pre> 標籤中,若要插入 10 行以上,請使用沙盒 (plnkrjsbincodepen…)