前端注釋規范


編寫代碼注釋的最佳實踐

好的注釋可以提高代碼的可讀性和可維護性,從而提高代碼質量。

作為研發同學,對於代碼“注釋”其實並不陌生。它往往作為我們代碼文檔的特殊補充而存在。

提倡加注釋,但不能濫用。我們開發流程中會有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,但因為一些原因還沒法修復;或者某個地方還有一些待完成的功能,這時我們需要使用相應的特殊標記注釋來告知未來的自己或合作者。常用的特殊標記有兩種:

  1. FIXME: 說明問題是什么

  2. 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規范

  1. no-warning-comments 開發者經常給代碼添加注釋,標明哪些沒有完成或需要審查。在你認為代碼可以發布之前,你很有可能想修復或審查代碼,然后刪除注釋。
  2. capitalized-comments 如果您不關心代碼庫中注釋的語法風格,則可以禁用此規則。控制注釋如果是英文首字母必須大寫
  3. line-comment-position 如果您不關心有不同的行注釋樣式,那么您可以關閉此規則。控制行注釋位置
  4. lines-around-comment 許多人喜歡簡潔的代碼風格,並且不介意與代碼沖突的評論。如果您屬於該類別,則此規則不適合您。 控制間隔評論,塊前空間。
  5. multiline-comment-style 如果您不想為多行注釋強制執行特定樣式,則可以禁用該規則。 控制多行注釋樣式。
  6. no-inline-comments 控制內聯注釋位置。
  7. spaced-comment 控制一些注釋間隔。

結論

我希望上面的例子已經表明注釋不能原諒或修復錯誤的代碼;它們通過提供不同類型的信息來補充好的代碼。

正如 Stack Overflow 聯合創始人 Jeff Atwood 所寫的那樣,“代碼告訴你如何,評論告訴你為什么。”

遵循這些規則應該可以節省您和您的隊友的時間和挫敗感。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM