正如我們在章節 程式碼結構 中所知,註解可以是單行:從 //
開始,也可以是多行:/* ... */
。
我們通常使用它們來描述程式碼如何運作以及原因。
乍看之下,註解似乎很明顯,但程式設計新手經常錯誤地使用它們。
糟糕的註解
新手傾向於使用註解來解釋「程式碼中發生了什麼事」。就像這樣
// This code will do this thing (...) and that thing (...)
// ...and who knows what else...
very;
complex;
code;
但在良好的程式碼中,這種「說明性」註解的數量應該是最小的。說真的,程式碼應該在沒有它們的情況下就能夠輕易理解。
關於這點有一個很棒的規則:「如果程式碼不清不楚到需要註解,那麼也許應該重新撰寫它」。
食譜:分解函式
有時將一段程式碼取代為一個函式是有益的,就像這裡
function showPrimes(n) {
nextPrime:
for (let i = 2; i < n; i++) {
// check if i is a prime number
for (let j = 2; j < i; j++) {
if (i % j == 0) continue nextPrime;
}
alert(i);
}
}
更好的變體,使用分解出來的函式 isPrime
function showPrimes(n) {
for (let i = 2; i < n; i++) {
if (!isPrime(i)) continue;
alert(i);
}
}
function isPrime(n) {
for (let i = 2; i < n; i++) {
if (n % i == 0) return false;
}
return true;
}
現在我們可以輕鬆理解程式碼了。函式本身就變成了註解。這種程式碼稱為自我描述。
食譜:建立函式
如果我們有一個像這樣的長「程式碼表」
// here we add whiskey
for(let i = 0; i < 10; i++) {
let drop = getWhiskey();
smell(drop);
add(drop, glass);
}
// here we add juice
for(let t = 0; t < 3; t++) {
let tomato = getTomato();
examine(tomato);
let juice = press(tomato);
add(juice, glass);
}
// ...
那麼將它重構為函式可能是更好的變體,例如
addWhiskey(glass);
addJuice(glass);
function addWhiskey(container) {
for(let i = 0; i < 10; i++) {
let drop = getWhiskey();
//...
}
}
function addJuice(container) {
for(let t = 0; t < 3; t++) {
let tomato = getTomato();
//...
}
}
再次地,函式本身說明了正在發生什麼事。沒有什麼好註解的。而且當程式碼被拆分時,結構也比較好。每個函式的功能、輸入和回傳值都很清楚。
在現實中,我們無法完全避免「說明性」註解。有複雜的演算法。而且有為了最佳化的目的而進行的聰明「調整」。但一般來說,我們應該試著讓程式碼保持簡單和自我描述。
好的註解
所以,說明性註解通常是不好的。哪些註解是好的?
- 描述架構
- 提供元件的高階概觀,它們如何互動,在各種情況下的控制流程是什麼…簡而言之,就是程式碼的鳥瞰圖。有一種特殊語言 UML 用於建立高階架構圖表來解釋程式碼。絕對值得學習。
- 記錄函式參數和用法
- 有一個特殊語法 JSDoc 用於記錄函式:用法、參數、回傳值。
例如
/**
* Returns x raised to the n-th power.
*
* @param {number} x The number to raise.
* @param {number} n The power, must be a natural number.
* @return {number} x raised to the n-th power.
*/
function pow(x, n) {
...
}
這樣的註解讓我們能夠理解函式的目的,並在不查看其程式碼的情況下正確使用它。
順帶一提,許多編輯器,例如 WebStorm,也可以理解它們,並使用它們來提供自動完成和一些自動程式碼檢查。
此外,還有像 JSDoc 3 這樣的工具,可以從註解中產生 HTML 文件。您可以在 https://jsdoc.dev.org.tw 閱讀有關 JSDoc 的更多資訊。
- 為何任務會以這種方式解決?
-
寫下來的內容很重要。但未寫下來的內容可能更重要,才能了解正在發生的事情。為何任務會以這種方式解決?程式碼沒有提供答案。
如果有多種方法可以解決任務,為何選擇這種方法?特別是當它並非最明顯的方法時。
沒有此類註解時,可能會發生以下情況
- 您(或您的同事)開啟一段時間前編寫的程式碼,並發現它「次佳」。
- 您想:「我當時有多愚蠢,現在又有多聰明」,並使用「更明顯且正確」的變體進行改寫。
- …改寫的衝動很好。但在這個過程中,您會發現「更明顯」的解決方案實際上是有缺陷的。您甚至隱約記得原因,因為您很久以前就已經嘗試過了。您改回正確的變體,但時間已經浪費了。
解釋解決方案的註解非常重要。它們有助於以正確的方式繼續開發。
- 程式碼的任何微妙特徵?它們在哪裡使用?
-
如果程式碼有任何微妙且反直覺的地方,絕對值得註解。
摘要
優秀開發人員的重要標誌是註解:它們的存在,甚至它們的缺失。
良好的註解讓我們能夠很好地維護程式碼,在延遲後重新檢視它,並更有效地使用它。
註解此內容
- 整體架構、高階檢視。
- 函式使用。
- 重要的解決方案,特別是不容易立即理解時。
避免註解
- 說明「程式碼如何運作」和「程式碼的作用」。
- 僅在無法讓程式碼變得如此簡單且具有自述性,而不需要它們時才將它們放入。
註解也用於自動文件編寫工具,例如 JSDoc3:它們會讀取註解並產生 HTML 文件(或其他格式的文件)。
註解
<code>
標籤,若要插入多行,請將其包裝在<pre>
標籤中,若要插入 10 行以上,請使用沙盒 (plnkr、jsbin、codepen…)