JavaScript之註釋規範化(JSDoc)


文章出自個人博客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 目錄中的相關網頁,就會展示類似於下面的頁面內容;

主頁:

jsdoc-home.png

指定函數頁:

jsdoc-func.png
網頁樣式模板也可以更換,根據命令行參數修改即可,這裏不再探究,下面主要來學習一下它的註釋格式;

註釋格式

完整的格式介紹請參考官網(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) {}
}

技術文章推送
手機、電腦實用軟件分享
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章