前端註釋規範
阿新 • • 發佈:2022-04-21
編寫程式碼註釋的最佳實踐
好的註釋可以提高程式碼的可讀性和可維護性,從而提高程式碼質量。
作為研發同學,對於程式碼“註釋”其實並不陌生。它往往作為我們程式碼文件的特殊補充而存在。
提倡加註釋,但不能濫用。我們開發流程中會有Code Review過程,這樣每個人都將瞭解好的註釋是什麼樣的,同時你遇到不好的程式碼註釋,也需要告訴他如何改進。
這裡有一些規則可以幫助我們把註釋寫的更好。
規則 1:註釋不應與程式碼重複。
規則 2:好的註釋不能成為不清晰程式碼的藉口。
規則3:如果不能寫清楚的註釋,可能是程式碼有問題。
規則 4:評論應該消除混亂,而不是引起混亂。
規則 5:在註釋中解釋單一的程式碼。
規則 6:提供複製程式碼的原始來源的連結。
規則 7:在最有幫助的地方包含指向外部參考的連結。
規則 8:修復錯誤時添加註釋。
規則 9:使用註釋來標記不完整的實現。
規則 1:註釋不應與程式碼重複。註釋不應重複程式碼的工作。應該去解釋程式碼的模型和心智模型的對映關係,應說明為什麼要使用這個程式碼模型,下面的例子就是反面教材:
// bad /** the name. */ let name:string; /** the version. */ let Version:string; /** the info. */ let info:string; // 使用給定的深度,在給定的子樹中查詢具有給定名稱的節點。 func FindNodeInSubtree(subTree *Node, name string, depth *int) *Node { }
規則 2:好的註釋不能成為不清晰程式碼的藉口。如起變數名時候取其實際含義,沒必要隨便寫個變數名然後在註釋裡面偷偷用功。起函式名時動詞+名詞結合。我們應當追求「程式碼自注釋」,即程式碼本身就擁有較高的可讀性(通過清晰的命名、合理的結構等)。 別害怕長名稱,長而具有描述性的名稱,比長註釋好。別害怕花時間取名字。
//bad // 如果已經準備好資料,就渲染表格 if (data.success && data.result.length > 0) { renderTable(data); } //good const isTableDataReady = data.success && data.result.length > 0; if (isTableDataReady) { renderTable(data); } //good init: function() { // 獲取配置資訊 const config = getConfig(); // 獲取使用者資訊 const userInfo = getUserInfo(); // 根據配置和使用者資訊,進行初始化 doInit(config, userInfo); // 如果存在自定義配置時的特殊邏輯 if (config.custom) { ... } }
規則 3:如果不能寫清楚的註釋,可能是程式碼有問題
**克尼根定律:布萊恩·克尼根正是與人合著了《C程式語言聖經》的人,以這條有見地的定律而聞名。關鍵在於:寫好程式碼,寫可讀程式碼,寫簡單程式碼,只要不是聰明的程式碼就行。
試圖用象牙塔的複雜性來鍛鍊你的程式設計能力,與編寫乾淨、更好的程式碼的意義恰恰相反。你的程式碼越難理解,當它不可避免地崩潰時,除錯就越困難。
規則 4:註釋應該消除混亂,而不是引起混亂。若程式語言足夠有表現力,我們就不需要註釋。程式碼在演化,註釋卻不總是隨之變動。不準確的註釋比沒註釋壞的多。寫為什麼做,少寫做了什麼。
``
規則 5:在註釋中解釋單一的程式碼
//bad,程式碼中不應該去解釋大家都能理解的程式碼,除非是在給新手編寫教程。
final Object value = (new JSONTokener(jsonString)).nextValue();
// Note that JSONTokener.nextValue() may return
// a value equals() to null.
if (value == null || value.equals(null)) {
return null;
}
規則 6:提供複製程式碼的原始來源的連結
/** 將可繪製物件轉換為點陣圖. via https://stackoverflow.com/a/46018816/2219998. */
return (int) (0.3 * red + 0.59 * green + 0.11 * blue);
規則 7:在最有幫助的地方包含指向外部參考的連結
/**
* Returns the current location object, which represents the current URL in web
* browsers.
*
* Note: If you're using this it may mean you're doing some of your own
* "routing" in your app, and we'd like to know what your use case is. We may
* be able to provide something higher-level to better suit your needs.
*
* @see https://reactrouter.com/docs/en/v6/api#uselocation
*/
export declare function useLocation(): Location;
規則 9:使用註釋來標記不完整的實現
即使程式碼中有已知的限制,有時還是有必要檢查它。雖然不分享程式碼中已知的缺陷很有誘惑力,但最好將這些明確化,例如使用TODO註釋:
// TODO(hal): We are making the decimal separator be a period,
// regardless of the locale of the phone. We need to think about
// how to allow comma as decimal separator, which will require
// updating number parsing and other places that transform numbers
// to strings, such as FormatAsDecimal
註釋規約
【推薦】單行註釋使用 //
註釋應單獨一行寫在被註釋物件的上方,不要追加在某條語句的後面:
// bad
const active = true; // is current tab
// good
// is current tab
const active = true;
註釋行的上方需要有一個空行(除非註釋行上方是一個塊的頂部),以增加可讀性:
// bad
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}
註釋行上面是一個塊的頂部時不需要空行
// good
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}
// good
function getType() {
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}
【推薦】多行註釋使用 /** ... */
,而不是多行的 //
// bad
// make() returns a new element
// based on the passed in tag name
function make(tag) {
// ...
return element;
}
// good
/**
* make() returns a new element
* based on the passed-in tag name
*/
function make(tag) {
// ...
return element;
}
【強制】註釋內容和註釋符之間需要有一個空格,以增加可讀性。eslint: spaced-comment
// bad
//is current tab
const active = true;
// good
// is current tab
const active = true;
// bad
/**
*make() returns a new element
*based on the passed-in tag name
*/
function make(tag) {
// ...
return element;
}
// good
/**
* make() returns a new element
* based on the passed-in tag name
*/
function make(tag) {
// ...
return element;
}
【推薦】使用特殊註釋標記。
有時我們發現某個可能的 bug,但因為一些原因還沒法修復;或者某個地方還有一些待完成的功能,這時我們需要使用相應的特殊標記註釋來告知未來的自己或合作者。常用的特殊標記有兩種:
-
FIXME: 說明問題是什麼
-
TODO: 說明還要做什麼或者問題的解決方案
class Calculator extends Abacus {
constructor() {
super();
// FIXME: shouldn’t use a global here
total = 0;
// TODO: total should be configurable by an options param
this.total = 0;
}
}
【推薦】文件類註釋,如函式、類、檔案、事件等,使用 jsdoc 規範
@see 這是JsDoc規範 這是連結 JsDoc規範。
JSDoc 是一個根據 JavaScript 檔案中註釋資訊,生成 JavaScript 應用程式或模組的API文件的工具。
/**
* Book類,代表一個書本.
* @constructor
* @param {string} title - 書本的標題.
* @param {string} author - 書本的作者.
*/
function Book(title, author) {
this.title=title;
this.author=author;
}
Book.prototype={
/**
* 獲取書本的標題
* @returns {string|*}
*/
getTitle:function(){
return this.title;
},
/**
* 設定書本的頁數
* @param pageNum {number} 頁數
*/
setPageNum:function(pageNum){
this.pageNum=pageNum;
}
};
【推薦】工具使用。我們可以使用一些工具來保證註釋質量,例如:
Eslint:保證一致的註釋風格ESLint 是當下最流行的 JS 程式碼檢查工具,ESLint 中有一些註釋相關的規則,使用者可選擇開啟:
@see 這是Eslint規範 這是連結 EsLint規範。
-
no-warning-comments
開發者經常給程式碼添加註釋,標明哪些沒有完成或需要審查。在你認為程式碼可以釋出之前,你很有可能想修復或審查程式碼,然後刪除註釋。 -
capitalized-comments
如果您不關心程式碼庫中註釋的語法風格,則可以禁用此規則。控制註釋如果是英文首字母必須大寫 -
line-comment-position
如果您不關心有不同的行註釋樣式,那麼您可以關閉此規則。控制行註釋位置 -
lines-around-comment
許多人喜歡簡潔的程式碼風格,並且不介意與程式碼衝突的評論。如果您屬於該類別,則此規則不適合您。 控制間隔評論,塊前空間。 -
multiline-comment-style
如果您不想為多行註釋強制執行特定樣式,則可以禁用該規則。 控制多行註釋樣式。 -
no-inline-comments
控制內聯註釋位置。 -
spaced-comment
控制一些註釋間隔。
結論
我希望上面的例子已經表明註釋不能原諒或修復錯誤的程式碼;它們通過提供不同型別的資訊來補充好的程式碼。
正如 Stack Overflow 聯合創始人 Jeff Atwood 所寫的那樣,“程式碼告訴你如何,評論告訴你為什麼。”
遵循這些規則應該可以節省您和您的隊友的時間和挫敗感。