文章出自個人博客https://knightyun.github.io/2020/03/13/js-comment-format,轉載請申明
前言
俗話說,無規矩不成方圓;雖說代碼敲出來都是交給編譯器解釋執行的,只要不存在語法格式錯誤,排版無論多麼反人類都是沒有問題的,但是代碼除了執行外的另一個廣泛用途就是閱讀了,翻閱自己過去的代碼、理解別人的源碼,等等;所以出現了代碼風格化,美化外觀的同時便於閱讀,這就是目前 JSLint 等工具的作用;
當然,除了代碼本身外,閱讀更多的可能就是代碼註釋了,註釋本身是不會被編譯器編譯執行的,其作用也是爲了留下一些信息,方便更好的理解代碼本身;所以,註釋的規範化也是一個值得思考的問題;而接下來即將介紹的 JSDoc 就是這樣的一款工具;
JSDoc
根據其官網(https://jsdoc.app/index.html)的介紹,JSDoc 是一個針對 JavaScript 的 API 文檔生成器,類似於 Java 中的 Javadoc 或者 PHP 中的 phpDocumentor;在源代碼中添加指定格式的註釋,JSDoc 工具便會自動掃描你的代碼並生成一個 API 文檔網站(在指定目錄下生成相關的網頁文件);
生成 API 文檔只是一方面,其更主要的貢獻在於對代碼註釋格式進行了規範化,你可能沒用過,但多半曾經在某個地方的源碼中見過類似於下面的註釋格式:
/**
* Returns the sum of a and b
* @param {number} a
* @param {number} b
* @returns {number}
*/
function sum(a, b) {
return a + b;
}
使用
工具的使用很簡單,首先安裝它:
npm install -g jsdoc
其次假設在一個名爲 doc.js
的文件中書寫以下代碼:
/**
* Returns the sum of a and b
* @param {number} a
* @param {number} b
* @returns {number}
*/
function sum(a, b) {
return a + b;
}
/**
* Return the diff fo a and b
* @param {number} a
* @param {number} b
* @returns {number}
*/
function diff(a, b) {
return a - b;
}
然後就是在當前目錄執行以下命令:
jsdoc doc.js
最後就會在當前目錄下生成一個名爲 out
的目錄(也可以另外指定),當前目錄內容就會變成像下面這樣:
├── doc.js
└── out
├── index.html
├── doc.js.html
├── global.html
├── fonts
│ ├── OpenSans-BoldItalic-webfont.eot
│ ├── OpenSans-BoldItalic-webfont.svg
│ ├── OpenSans-BoldItalic-webfont.woff
│ ├── OpenSans-Bold-webfont.eot
│ ├── OpenSans-Bold-webfont.svg
│ ├── OpenSans-Bold-webfont.woff
│ ├── OpenSans-Italic-webfont.eot
│ ├── OpenSans-Italic-webfont.svg
│ ├── OpenSans-Italic-webfont.woff
│ ├── OpenSans-LightItalic-webfont.eot
│ ├── OpenSans-LightItalic-webfont.svg
│ ├── OpenSans-LightItalic-webfont.woff
│ ├── OpenSans-Light-webfont.eot
│ ├── OpenSans-Light-webfont.svg
│ ├── OpenSans-Light-webfont.woff
│ ├── OpenSans-Regular-webfont.eot
│ ├── OpenSans-Regular-webfont.svg
│ └── OpenSans-Regular-webfont.woff
├── scripts
│ ├── linenumber.js
│ └── prettify
│ ├── Apache-License-2.0.txt
│ ├── lang-css.js
│ └── prettify.js
└── styles
├── jsdoc-default.css
├── prettify-jsdoc.css
└── prettify-tomorrow.css
通過瀏覽器訪問這個 out
目錄中的相關網頁,就會展示類似於下面的頁面內容;
主頁:
指定函數頁:
網頁樣式模板也可以更換,根據命令行參數修改即可,這裏不再探究,下面主要來學習一下它的註釋格式;
註釋格式
完整的格式介紹請參考官網(https://jsdoc.app/index.html),目前版本是 JSDoc 3,下面只介紹幾種常用的標籤並配合舉例;當然如果嫌手寫一堆標籤麻煩,現在許多編輯器(比如 VS Code)都提供了相關的插件下載,直接在插件中搜索關鍵詞 jsdoc 就會出現許多,都是帶提示或者自動識別當前代碼生成的,很方便;
註釋符
JSDoc 使用以下格式的註釋符來對要添加的標籤進行塊級包裹:
/**
*
*
*/
即星號列垂直對其,第一行使用兩個星號,每個星號後要添加一個空格再寫內容,比如:
/**
* 前面留一個空格,再寫描述
* 或者多行描述
* @param {number} 關於該參數的描述
*/
行內包裹:
/** @function */
@description
也可寫作 @desc
,描述當前註釋對象的詳細信息;
/**
* @function
* @description 關於該函數的介紹內容
*/
function myFn() {}
/**
* 也能在這裏直接寫介紹內容
* @function
* @description 如果這裏又繼續使用標籤添加內容,則會覆蓋第一行的介紹內容
*/
function myFn() {}
@file
註釋寫在文件開頭,用於描述當前文件的相關信息;例如:
/**
* @file 這是一個用於...的文件,包含了...功能
*/
// 然後是代碼正文...
@author
描述當前文件或者代碼的作者的相關信息;
/**
* @author Jack <[email protected]>
*/
@copyright
描述當前文件的版權相關信息
/**
* @copyright Jack 2020
*/
@license
描述當前文件許可證相關信息;
/**
* @license MIT
*/
或者是:
/**
* @license
* Copyright (c) 2015 Example Corporation Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* ...
*/
@version
描述當前項目的版本號;
/**
* 這個版本修復了...問題
* @version 1.2.3
*/
@since
描述某個功能是從哪個版本開始引入的;
/**
* 提供了...功能
* @since 1.2.1
*/
function newFn() {}
@see
類似於“另見”、“詳見"的意思,引導至其他位置,也可以使用 @link
引導至某一網絡地址;
/**
* @see fn2
*/
function fn1() {}
/**
* @see {@link http://example.com|some text}
*/
function fn2() {}
@todo
描述接下來準備做的事情;
/**
* @todo 添加...功能
* @todo 修復...bug
*/
function myFn() {}
@function
與 @func
, @method
含義相同,描述一個函數;
/** @function */
var myFn = function() {}
@type
描述一個變量的類型;
/**
* 一個對象類型的變量
* @type {object}
*/
var val1 = {};
/**
* 一個字符或者數字類型的變量
* @type {(string|number)}
*/
var val2;
/**
* 類型爲數字或爲空
* @type {?number}
*/
var val3;
/**
* 類型爲數字或且不能爲空
* @type {!number}
*/
var val4;
/**
* 一個 MyClass 類的實例數組
* @type {Array.<MyClass>}
*/
var arr = new MyClass();
/**
* 一個字符串的數組
* @type {string[]}
*/
var arr2 = ['a', 'b', 'c'];
/**
* 一個包含一個字符串和一個數字類型的對象
* @type {object.<string, number>}
*/
var obj1 = {a: 'one', b: 2}
/**
* 指定具體鍵和類型的對象
* @type {{a: string, b: number}}
*/
var obj2 = {a: 'one', b: 2}
/**
* 指定具體鍵和類型的命名對象
* @type {object} obj3
* @type {string} obj3.a
* @type {number} obj3.b
*/
var obj3 = {a: 'one', b: 2}
@param
與 @arg
, @argument
含義相同,描述一個函數的參數信息;
/**
* 標籤後跟參數類型,然後是參數名,最後是參數描述
* @param {number} a 這裏寫變量的描述
* @param {string} b - 或者加上連字符便於閱讀
* @param {string} c - 又或者這個參數有一個很長很長很長
* 很長很長很長很長很長非常長的描述,可以這樣佔用多行
*/
function myFn(a, b, c) {}
/**
* 傳入的參數是個對象
* @param {object} option - 傳入的對象參數
* @param {string} option.name - 對象的 name 屬性
* @param {number} option.age - 對象的 age 屬性
*/
function myFn(option) {
var name = option.name;
var age = option.age;
}
/**
* 傳入的參數是個字符串組成的數組
* @param {string[]} arr - 傳入的對象參數
*/
function myFn(arr) {
var name = option.name;
var age = option.age;
}
/**
* 表示某個參數是可選的
* @param {number} a - 這是必填參數
* @param {number} [b] - 這是可選參數
* @param {number=} c - 可選參數的另一種表示
*/
function myFn(a, b, c) {}
/**
* 表示可選參數的默認值
* @param {number} a
* @param {number} [b=3] - 默認值爲 3
*/
function myFn(a, b) {}
/**
* 參數類型的各種表示
* @param {number} a - 類型爲數字
* @param {number|string} b - 類型爲數字或字符串
* @param {?number} c - 類型爲數字或者爲空(null)
* @param {!number} d - 類型爲數字且不爲空
* @param {*} e - 類型不做限制,即可以爲任意類型
*/
function myFn(a, b, c, d, e) {}
/**
* 表示具有任意多個參數的函數
* 下面的函數返回所有傳入參數的和
* @param {...number} num - 參數個數任意,但是都是數字類型
*/
function sum(num) {
var len = arguments.length;
var result = 0;
for (let i = 0; i < len; i++) {
result += arguments[i];
}
return result;
}
@typedef
用於描述自定義的變量類型;
/**
* 關於自定義類型的描述
* @typedef {(string|number)} myType
*/
/**
* 關於自定義類型的描述
* @type {myType} val - 使用自定義的類型
*/
function myFn(val) {}
@callback
描述指定函數中作爲回調函數的參數信息;
/**
* 這是關於回調函數的描述
* @callback myCallback
* @param {string} aa - 回調函數接受的參數
* @param {number} [bb] - 回調函數接受的另一個可選參數
*/
/**
* 這是關於函數本身的描述
* @param {string} a
* @param {myCallback} callback - 回調函數
*/
function myFn(a, callback) {}
@returns
或者寫作 @return
,描述函數的返回值的信息;
/**
* @param {number} a
* @returns {number} 關於返回值的描述
*/
function myFn(a) {
return a + 1;
}
/**
* @param {number} a
* @returns {(number|string)} 返回值可能是數字或字符類型
*/
function myFn2(a) {
if (a > 1) {
return 1;
} else {
return 'no.';
}
}
@example
描述指定代碼的使用示例;
/**
* 添加示例代碼(格式會被高亮展示)
* @param {string} a
* @param {string} b
* @returns {string} return a concat b.
*
* @example
* console.log(myFn('hello ', 'world!'));
* // "hello world!"
*/
function myFn(a, b) {
return a + b;
}
@class
描述一個 class
類;
/**
* 關於該類的描述
* @class
*/
class MyClass {}
/**
* 或者是一個構造函數
* @class
*/
function MyClass() {}
var ins = new MyClass();
@namespace
描述一個命名空間;
/**
* 指定一個對象對命名空間
* @namespace
*/
var MyNamespace = {
/**
* 表示爲 MyNamespace.fn
* @returns {*}
*/
fn: function() {},
/**
* 表示爲 MyNamespace.a
* @type {number}
*/
a: 1
}
/**
* 手動指定命名空間
* @namespace MyNamespace
*/
/**
* 一個成員函數,MyNamespace.myFn
* @function
* @returns {*}
* @memberof MyNamespace
*/
function myFn() {}
@member
描述當前類的一個成員;
/**
* @class
*/
function MyClass() {
/** @member {string} */
this.name = 'knightyun';
/**
* 或者一個虛擬的成員
* @member {number} age
*/
}
@memberof
描述成員所屬的類;
/**
* @class
*/
class MyClass {
/**
* @constructor
* @memberof MyClass
*/
constructor() {}
/*
* @param {string} val
* @returns {*}
* @memberof MyClass
*/
myFn(val) {}
}