JavaScript文档注释深入讲解(非常详细)
作者:少莫千华
什么是文档注释
在JavaScript中,文档注释是一种特殊的注释格式,用于描述代码的功能、使用方法、参数、返回值等信息。文档注释通常使用特定的注释标记和结构来表示,并且可以通过工具解析生成文档。
在JavaScript中,常用的文档注释格式是使用 /** 和 */ 括起来的多行注释。例如:
/** * 这是一个示例函数,用于加法运算。 * @param {number} a - 第一个操作数 * @param {number} b - 第二个操作数 * @returns {number} - 两个操作数的和 */ function add(a, b) { return a + b; }
上面的代码段中,以 /** 开始和以 */ 结束的多行注释就是文档注释。在注释的内容中,使用了一些特殊的标记来表示相关信息,比如 @param 表示参数,@returns 表示返回值。可以在这些标记后面添加具体的描述和类型信息。
为什么要写文档注释
编写JavaScript的文档注释有助于提高代码的可读性、生成易于阅读的API文档、明确接口规范、辅助调试和维护工作,以及促进团队合作和知识共享。这是为了更好地组织和记录代码,并使其更易于理解和使用的最佳实践之一。
- 提供代码的可读性:文档注释可以帮助其他开发人员更好地理解你的代码。通过提供清晰的注释,可以解释代码的目的、使用方法和重要细节,使代码更易于阅读和维护。
- 自动生成文档:许多开发工具和框架可以根据代码中的文档注释来自动生成文档。例如,JSDoc 是一个常用的JavaScript文档生成工具,它可以解析文档注释并生成API文档。这样其他开发人员就可以轻松地查看代码的接口和用法。
- 提供接口定义和规范:通过文档注释,可以明确说明函数、类、方法和参数的用途、类型和预期行为。这不仅帮助其他开发人员正确使用你的代码,还可以在团队协作中提供一致性和规范。
- 辅助代码调试和维护:当你在调试和维护代码时,文档注释可以提供有关代码功能和实现细节的重要信息。这对于理解复杂的功能和排查问题非常有帮助,尤其是当你需要处理他人编写的代码或长时间未接触的代码时。
- 促进团队合作和知识共享:文档注释可以为开发团队提供一个共享的知识库,使所有人都能理解代码的功能和实现细节。这有助于提高团队成员之间的沟通和协作,并促进代码质量和一致性。
//
行注释对于编辑器来说是无效的注释,虽然func
从名字上看上去应该是一个方法,但是编辑器(vscode
)不知道它是一个函数
// 函数防抖 function debounce(func,duration = 1000) { }
当鼠标放到函数上时,编辑器并不知道这个函数的功能是“函数防抖”
当鼠标放到参数func
上时,编辑器并不知道这个参数是函数
不使用文档注释存在的隐患
使用函数成员时的书写问题
在使用函数成员时,能有效的降低书写错误。因此,你在使用函数里面的一些成员的时候
// 函数防抖 function debounce(func,duration = 1000) { func.aply }
如:当你在debounce
函数内部使用func.apply
,它没有智能提示,因为它不知道apply
是一个函数
那你稍微不注意把单词写错成aply
,就增加了出错的几率啊。
在开发过程中,有相当一部分程序问题就是由于单词拼写错误导致的。
有人又说了有AI智能提示不是比文档注释更好用吗?
虽然TypeScript(AI自动补全)就是来解决这个单词书写错误的问题的,毕竟很多项目里面没有上TypeScript (AI自动补全)。这工具也不是你想用就能用的,他涉及到隐私、费用、不支持等等原因。所以TypeScript
只能起到锦上添花的作用。
调用函数时功能使用问题
// 函数防抖 function debounce(func,duration = 1000) { } debounce
在debounce
函数使用的时候我们能从这个单词的含义知道,它是一个防抖函数,如果我们把这个函数的名称改成wefwfas
,我们不知道他的作用是什么,使用的时候没有任何提示,只知道要传2个参数,至于参数的含义、类型等等都不知道。因此我们最好是写文档注释。
// 函数防抖 function wefwfas(func,duration = 1000) { } wefwfas
/** * * @param {*} func * @param {*} duration */ function wefwfas(func,duration = 1000) { }
文档注释
官方标签
函数
如下我们可以给函数写一个注释函数防抖:
/** * 函数防抖 * @param {*} func * @param {*} duration */ function debounce(func,duration = 1000) { } debounce()
当鼠标放到函数上时,它就会提示这个函数的名字是函数防抖
当我们使用的时候,同样的可以看到它是函数防抖的函数
由于平时封装的函数日积月累,如果不添加文档注释的话,很多函数都忘记其作用了。
参数标签 @param
参数类型 {}
针对函数每一个参数也可以添加文档注释,其中以关键字param
(parameter) 开始,格式如下:
* @param {<type>} <param-name> <comments>
-
param
: 参数关键字 -
<type>
: 参数类型,*
- 支持接收所有类型Number
- 只接收一种Function|Number
- 兼容多种
-
<param-name>
: 名称 -
<comments>
: 参数说明
如下所示:
- 参数
func
类型是Function
- 参数
duration
类型是Number
/** * 函数防抖 * @param {Function} func * @param {Number} duration */ function debounce(func,duration = 1000) { } debounce()
当我们把鼠标放到这个参数上时,编辑器就知道
func
是函数。
/** * 函数防抖 * @param {Function} func * @param {Number} duration */ function debounce(func,duration = 1000) { func.call } debounce()
所以在实现这个函数的时候,当我们使用func.apply
、func.call
这些函数方法的时候都有提示了。
当我们需要调用这个函数时,鼠标放到调用的函数上的时候,编辑器就会告诉我这个参数是一个函数。
参数注释
可以给这个参数呢加上注释,如下示例
/** * 函数防抖 * @param {Function} func 防抖的目标函数 * @param {Number} duration 函数执行前等待的时间 */ function debounce(func,duration = 1000) { } debounce()
现在我们再用鼠标放到参数上看看编辑器会怎么提示我们:
对象属性属性注释
如果参数是object
我们还可以对object的每个属性单独添加注释
``
/** * 网络请求 * @param {object} options 配置对象 * @param {string} options.url 请求地址 * @param {'GET'|'POST'} options.method 请求方法 * @param {object} options.body * @param {object} options.headers */ async function request(options) { }
url
- 是字符串method
- 是字符串选项,可以是GET
也可以是POST
body
- 是对象headers
- 是对象
使用带有对象属性注释的参数
/** * 网络请求 * @param {object} options 配置对象 * @param {string} options.url 请求地址 * @param {'GET'|'POST'} options.method 请求方法 * @param {object} options.body * @param {object} options.headers */ async function request(options) { } request()
我们看看编辑器会怎么提示我们:
返回值标签 @returns
针对有返回值函数可以添加返回值的注释,其中以关键字returns
开始,格式如下:
* @returns {<type>} <comments>
-
returns
: 返回值关键字 -
<type>
: 参数类型,*
- 支持接收所有类型Number
- 只接收一种Function|Number
- 兼容多种
-
<comments>
: 参数说明
/** * 函数防抖 * @param {Function} func 防抖的目标函数 * @param {Number} duration 函数执行前等待的时间 * @returns {Function} 返回一个防抖的函数 */ function debounce(func,duration = 1000) { } debounce()
这样返回值的类型也确定下来了,我们看看编辑器是怎么提示我们的:
作者标签 @author
可以添加作者有关的注释,其中以关键字author
开始,格式如下:
* @author <author-name> <contact-way>
-
author
: 作者信息关键字 -
<author-name>
: 作者姓名 -
<contact-way>
: 联系方式,可以是个人网页、邮箱等等。例如:<370763160@qq.com>
/** * 函数防抖 * @author ISail <370763160@qq.com> * @param {Function} func 防抖的目标函数 * @param {Number} duration 函数执行前等待的时间 * @returns {Function} 返回一个防抖的函数 */ function debounce(func,duration = 1000) { } debounce()
我们看看编辑器会怎么提示我们,点击<370763160@qq.com>
还可以发邮件。
许可证标签 @license
可以添加版权有关的注释,其中以关键字license
开始,格式如下:
* @license <license-info>
-
license
: 版权信息关键字 -
<license-info>
: 指定代码的许可证信息。可以显示多行
在使用 @license 标签时,开发者应该根据代码的实际许可情况填写适当的许可证信息。这有助于提供清晰的许可证声明,保护代码的知识产权,并促进合规和合理的代码使用。
许可证分类
1. 开源许可证(Open Source Licenses)
这些许可证基于开源原则,允许使用、修改和分发源代码或衍生作品。常见的开源许可证包括MIT
许可证、BSD
许可证、Apache许可证等。
下面是各种常见许可证之间的差异的详细比较表格
:
许可证 | 类型 | 商业使用 | 分发修改 | 源代码发布 | 声明更改 | 分发条件 | 专利许可 | 网络服务使用 | 许可证嵌入 |
---|---|---|---|---|---|---|---|---|---|
GPL | 强保护 | 否 | 是 | 是 | 是 | Copyleft | 是 | 是 | 否 |
LGPL | 弱保护 | 是 | 是 | 可选 | 是 | 空白条件 | 否 | 是 | 是 |
AGPL | 强保护 | 否 | 是 | 是 | 是 | 空白条件 | 是 | 是 | 否 |
New BSD | 自由 | 是 | 是 | 是 | 是 | 空白条件 | 否 | 是 | 是 |
Simple BSD | 自由 | 是 | 是 | 是 | 否 | 空白条件 | 否 | 是 | 是 |
MIT | 自由 | 是 | 是 | 是 | 是 | 空白条件 | 否 | 是 | 是 |
Apache | 自由 | 是 | 是 | 是 | 是 | 空白条件 | 是 | 是 | 是 |
Apache 2.0 | 自由 | 是 | 是 | 是 | 是 | 空白条件 | 是 | 是 | 是 |
MPL | 弱保护 | 是 | 是 | 是 | 是 | 空白条件 | 是 | 是 | 是 |
Mozilla MPL 2 | 弱保护 | 是 | 是 | 是 | 是 | 空白条件 | 是 | 是 | 是 |
CDDL | 弱保护 | 是 | 是 | 是 | 是 | 空白条件 | 是 | 是 | 是 |
CPL | 弱保护 | 是 | 是 | 是 | 是 | 空白条件 | 是 | 是 | 是 |
EPL | 弱保护 | 是 | 是 | 是 | 是 | 空白条件 | 是 | 是 | 是 |
CC | 弱保护 | 是 | 是 | 是 | 是 | 空白条件 | 否 | 是 | 是 |
CC0 | 自由 | 是 | 是 | 是 | 否 | 空白条件 | 否 | 是 | 是 |
WTFPL | 自由 | 是 | 是 | 是 | 否 | 空白条件 | 否 | 是 | 是 |
下面是各列的解释:
- 类型:许可证类型,分类为 “强保护”(对派生作品有限制)和 “弱保护”(提供更大的自由度)。
- 商业使用:许可证是否允许商业使用。
- 分发修改:许可证是否允许分发修改后的代码。
- 源代码发布:许可证是否要求源代码的公开发布。
- 声明更改:许可证是否要求在修改后的代码中声明更改。
- 分发条件:许可证对分发软件的条件要求。
- 专利许可:许可证是否授予使用专利的权利。
- 网络服务使用:许可证是否允许使用者基于该软件提供网络服务。
- 许可证嵌入:许可证是否要求在使用软件的产品中嵌入许可证信息。
请注意,这个表格只提供了对常见许可证之间的主要差异的概述。具体的许可证条款和条件应该参考每个许可证的官方文档和相关说明。选择适当的许可证需要根据项目需求和法律咨询进行综合考虑。另外,这里列出的是一些常见的开源许可证,而还有其他类型的许可证可供选择。
2. 版权声明(Copyright Declaration)
这种分类主要用于声明代码的版权归属,指明作者或组织对代码的所有权。在这种情况下,@license 标签通常包含版权声明和版权所有者的信息。
/** * @license * * 项目一 版本1.0.0 * (c) 2023年 ISail * 根据“项目一许可证”发布。 * * https://www.example.com/licenses/myproject-license */
在这个例子中,我们假设一个名为 “项目一” 的项目,作者为 ISail
。他在注释中使用 @license
标签来声明版权信息。下面是每个部分的解释:
- 项目一 版本1.0.0:指定了项目的版本号。
- (c) 2023年 ISail:声明了版权归属于 ISail,即声明了版权归属于,又指明了版权年份。
- 根据“项目一”许可证发布。:说明代码是根据 “项目一许可证” 发布的。
- https://www.example.com/licenses/project1-license:提供了一个链接,指向一个包含详细许可证条款的网页。
3. 私有许可证(Proprietary Licenses)
私有许可证用于保护代码的知识产权,限制未经许可的使用和分发。在这种情况下,@license 标签可能包含具体的许可条款和使用限制,以及联系方式以获取许可。
/** * @license * * 库一 版本2.0.0 * (c) 2023年 少莫千华无限公司。 保留所有权利。 * * 这是一款私有软件。严禁未经授权擅自复制或传播本软件或其任何部分。 * * 如需咨询许可证相关信息, 请联系: * 370763160@qq.com */
在这个例子中,我们假设一个名为 “库一” 的库,归属于 少莫千华无限公司。。作者明确声明了版权信息,并添加了与私有许可证相关的说明。下面是每个部分的解释:
- 库一 版本2.0.0:指定了库的版本号。
- (c) 2023年 少莫千华无限公司。 保留所有权利。:声明了版权归属于少莫千华无限公司。,并表示保留所有权利。
- 这是一款私有软件。严禁未经授权擅自复制或传播本软件或其任何部分。:明确说明这是一款私有软件,未经许可严禁复制或分发软件或其任何部分。
- 如需咨询许可证相关信息, 请联系:370763160@qq.com:提供了一个联系方式,以便进行许可证相关的咨询。
4. 其他许可证(Other Licenses)
这个分类用于指定其他不属于常见类别的特定许可证。
/** * @license * * 项目一 版本1.0.0 * (c) 2023年 ISail * 根据Apache许可证2.0发布 * * SPDX-License-Identifier: Apache-2.0 * * 了解更多信息,请访问: * https://www.apache.org/licenses/LICENSE-2.0 */
在这个例子中,我们假设一个名为 “项目一” 的项目,作者为 ISail
。他在注释中使用 @license
标签来声明版权信息,并指定了使用的许可证。下面是每个部分的解释:
- 项目一 版本1.0.0:指定了项目的版本号。
- (c) 2023年 ISail:声明了版权归属于 ISail,并指明了版权年份。
- 根据Apache许可证2.0发布:说明代码是根据 Apache License 2.0 发布的。
- SPDX-License-Identifier: Apache-2.0使用 SPDX许可证标识符明确指定了所采用的许可证。
- https://www.apache.org/licenses/LICENSE-2.0:提供了一个链接,指向一个包含详细许可证条款的网页。
/** * 函数防抖 * @author ISail <370763160@qq.com> * @license MIT * @param {Function} func 防抖的目标函数 * @param {Number} duration 函数执行前等待的时间 * @returns {Function} 返回一个防抖的函数 */ function debounce(func,duration = 1000) { } debounce()
示例标签 @example
可以在注释中添加示例,提示如何使用这个函数,其中以关键字example
开始,格式如下:
/** * 获取指定范围内的随机整数 * @param {number} min 随机数的最小值 * @param {number} max 随机数的最大值 * @return {number} 随机数 * @example * getRange(1, 10); // 获取[1,10]之间的随机数 */ function getRandom(min, max) { } getRandom
我们看看编辑器会怎么提示我们:
定义对象标签 @typedef 和属性标签 @property
在下面的例子中,使用@typedef
关键字定义了一个名为User
的类型别名,并使用@property
关键字指定了User
对象的各个属性及其类型。接下来,getUserInfo
函数使用@param
关键字指定了参数userId
的类型为number
,并使用@returns
关键字指定了返回值类型为User`对象。
通过使用@typedef
关键字,我们可以在文档注释中清晰地指定变量、属性和函数的类型,提高代码可读性和可维护性。
/** * 用户对象 * @typedef {object} User * @property {number} id - 用户ID * @property {string} name - 用户名 * @property {string} email - 用户电子邮箱 * @property {Date} birthday - 用户生日 */ /** * 获取用户信息 * @param {number} userId - 用户ID * @returns {User} - 返回用户对象 */ function getUserInfo(userId) { // ... } const user = getUserInfo(123); console.log(user.name); // 输出用户的用户名
我们看看编辑器会怎么提示我们:
异常标签 @throws
在下面的例子中,divide
函数使用@param
关键字指定了两个参数的类型为number
,使用@returns
关键字指定了返回值类型为number
,并使用@throws
关键字指定了可能抛出的异常类型为Error
。在函数内部,通过判断除数是否为0,如果是则抛出一个错误。
通过使用@throws
关键字,我们可以提示其他开发者该函数可能抛出的异常,使其在调用函数时能够更好地处理异常情况。而在调用函数处,可以使用try...catch
语句捕获并处理异常,避免程序崩溃。
/** * 执行除法运算 * @param {number} dividend - 被除数 * @param {number} divisor - 除数 * @returns {number} - 返回除法结果 * @throws {Error} 如果除数为0,则抛出错误 */ function divide(dividend, divisor) { if (divisor === 0) { throw new Error("除数不能为0"); } return dividend / divisor; } try { const result = divide(10, 0); console.log(result); } catch (error) { console.error(error.message); }
我们看看编辑器会怎么提示我们:
废弃标签 @deprecated
在下面的例子中,通过使用@deprecated
关键字,我们将原来的add函数标记为已废弃,并在注释中说明了该函数已被废弃,建议使用新的addNumbers
函数代替。在代码中,我们首先调用了已废弃的add
函数来计算两个数字的和,然后使用新的addNumbers
函数来计算多个数字的和。
/** * @deprecated 该函数已被废弃,请使用新的 addNumbers 函数代替。 * 将两个数字相加 * @param {number} a - 第一个数字 * @param {number} b - 第二个数字 * @returns {number} - 返回相加的结果 */ function add(a, b) { return a + b; } /** * 将多个数字相加 * @param {...number} numbers - 要相加的数字列表 * @returns {number} - 返回相加的结果 */ function addNumbers(...numbers) { return numbers.reduce((sum, number) => sum + number, 0); } console.log(add(2, 3)); // 输出: 5 console.log(addNumbers(2, 3, 4)); // 输出: 9
我们看看编辑器会怎么提示我们:
约定标签
成员的可见性 @private @protected @public
- _xxxx - 私有成员
- @private - 私有成员
- @protected - 保护成员
- @public- 公共成员
在下面的例子中,我们使用了下划线 _ 来约定将属性标记为私有,以表示该属性应该被视为私有成员。在构造函数中,我们使用注释@private来说明该属性是私有的。而在getName方法中,我们并没有使用注释@private,因为该方法是公共的,可以由外部访问。
/** * 创建一个动物类 * @class */ class Animal { /** * 构造函数 * @param {string} name - 名称 * @private */ constructor(name) { this.name = name; // 公共属性 this._age = 0; // 私有属性,约定以 "_" 开头 this._weight = 0; // 私有属性,约定以 "_" 开头 } /** * 公共方法 - 获取名称 * @returns {string} - 返回名称 * @public */ getName() { return this.name; } /** * 保护方法 - 获取年龄 * @returns {number} - 返回年龄 * @protected */ _getAge() { return this._age; } } /** * 创建一个狗类,继承自动物类 * @class */ class Dog extends Animal { /** * 构造函数 * @param {string} name - 名称 */ constructor(name) { super(name); this.breed = "unknown"; // 公共属性 } /** * 公共方法 - 获取品种 * @returns {string} - 返回品种 * @public */ getBreed() { return this.breed; } /** * 公共方法 - 获取年龄和名称 * @returns {string} - 返回年龄和名称的字符串 * @public */ getAgeAndName() { const age = this._getAge(); // 子类可以访问父类的保护方法 return `Age: ${age}, Name: ${this.name}`; } } const animal = new Animal("Animal"); console.log(animal.name); // 可以直接访问公共属性 "name" console.log(animal._age); // 仍然可以直接访问约定为私有的属性 "_age" const dog = new Dog("Dog"); console.log(dog.name); // 可以直接访问公共属性 "name" console.log(dog.breed); // 可以直接访问公共属性 "breed" console.log(dog._getAge()); // 子类可以调用父类的保护方法 "_getAge" console.log(dog._age); // 仍然可以直接访问约定为私有的属性 "_age" console.log(dog.getAgeAndName()); // "Age: 0, Name: Dog"
在上面的例子中,我们使用了命名约定和注释来模拟 @private
、@public
、@protected
关键字。约定是使用 _
开头将属性标记为私有,不使用任何特殊约定将属性标记为公共的。
- name 属性在 Animal 类中是公共的,可以通过对象实例直接访问。
- _age 属性和 _getAge 方法在 Animal 类中被约定为私有的,但是在 Dog 类中仍然可以直接访问。
- breed 属性和 getBreed 方法在 Dog 类中是公共的,可以通过对象实例直接访问。
- getAgeAndName 方法在 Dog 类中访问了父类Animal 的 _getAge 方法。
请注意,这些约定只是一种标准做法,实际上并不能真正实现属性或方法的私有性或保护性。开发者仍然可以绕过约定直接访问被标记为私有的属性。然而,通过使用约定和注释,我们可以向其他开发者传达哪些成员应该被视为私有或保护,以遵循封装的原则。
类 @class 的继承 @extends 与方法的重写 @inheritdoc
/** * 车辆类 * @class */ class Vehicle { /** * 构造函数 * @param {string} brand - 品牌 */ constructor(brand) { this.brand = brand; // 公共属性 } /** * 获取品牌信息 * @returns {string} - 返回品牌信息 */ getBrand() { return this.brand; } } /** * 汽车类,继承自车辆类 * @class * @extends Vehicle */ class Car extends Vehicle { /** * 构造函数 * @param {string} brand - 品牌 * @param {string} model - 型号 */ constructor(brand, model) { super(brand); this.model = model; // 公共属性 } /** * @inheritdoc */ getBrand() { return super.getBrand(); } /** * 获取车辆信息,包括品牌和型号 * @returns {string} - 返回车辆信息 */ getVehicleInfo() { const brand = this.getBrand(); // 调用父类的方法 return `Brand: ${brand}, Model: ${this.model}`; } } const car = new Car("Toyota", "Camry"); console.log(car.getVehicleInfo()); // "Brand: Toyota, Model: Camry"
在上面的例子中,我们使用了 @extends
标签来说明 Car
类继承自 Vehicle
类。然后,在 getBrand
方法的文档注释中使用了 @inheritdoc
标签来表示该方法继承并重写了父类的方法。
请注意,这里的 @inheritdoc
标签只是一种约定,并不是 JavaScript
文档注释的官方标签。不同的文档生成工具可能会对此标签有不同的处理方式。因此,在实际开发中,你需要根据你所使用的文档生成工具的要求来使用适当的标签或约定。
类型 @type 与只读 @readonly
/** * 用户类 * @class */ class User { /** * 创建一个用户实例 * @param {string} name - 名称 */ constructor(name) { /** * 用户名称 * @type {string} */ this.name = name; /** * 用户ID,只读属性 * @type {number} * @readonly */ this.id = generateUniqueId(); } } const user = new User("Alice"); console.log(user.name); // "Alice" console.log(user.id); // 使用只读属性,例如:"123456" user.name = "Bob"; // 可以修改可写属性 user.id = 789; // 尝试修改只读属性,会导致错误
在上述示例中,@readonly
标签用于描述 User 类中的 id 属性。这告诉开发人员该属性是只读的,不能在实例创建后进行修改。这样,开发人员在使用该类时就会知道如何正确操作属性。
请注意,JSDoc 标签是一种约定,不同的工具可能会在生成文档时以不同的方式处理标签。但是,@readonly
是在 JSDoc 规范中定义的标准标签之一,并且受到广泛支持。因此,它被认为是官方标签。
类 @class 与构造函数 @constructor
/** * 表示一个人的类 * @class */ class Person { /** * 创建一个人的实例 * @constructor * @param {string} name - 名字 * @param {number} age - 年龄 */ constructor(name, age) { this.name = name; this.age = age; } } // 创建一个人的实例 const person = new Person("Alice", 25); console.log(person.name); // "Alice" console.log(person.age); // 25
在上述示例中,@class
标签用于描述 Person
类,它表示一个人的类。类的构造函数使用 @constructor
标签进行注释,以指示这是一个构造函数。
构造函数的文档注释使用 @param
标签描述参数,name
参数表示名字,age
参数表示年龄。这样,在使用该类时,开发人员可以通过文档了解到构造函数所需的参数和其作用。
通过使用 @class
和 @constructor
标签,可以为 JavaScript
类提供清晰的文档注释,使其他开发人员能够更好地理解和使用该类。
自定义标签
请注意,JSDoc
并不对自定义标签提供原生的支持,所以某些工具可能会忽略或不同程度地支持这些标签。但是,通过约定和规范,您可以为您的代码库添加自定义信息,以便更好地记录代码的演化历史。
历史记录@history
/** * 计算两个数字的和 * @param {number} a - 第一个数字 * @param {number} b - 第二个数字 * @returns {number} 两个数字的和 * @history * - 2021-01-01 初始版本 * - 2022-05-15 修复 bug:处理负数的情况 */ function addNumbers(a, b) { return a + b; }
在上述示例中,自定义的 @history
标签被用来记录代码的发展历程。每一行记录都包含日期和相应的注释。
使用这种方式,您可以在 JSDoc
注释中记录多个版本、修复或改进的历史信息。这样,其他开发人员在查看文档时可以了解到代码的进展和变化。
日期@history
/** * 计算两个数字的和 * @param {number} a - 第一个数字 * @param {number} b - 第二个数字 * @returns {number} 两个数字的和 * @date 2021-01-01 初始版本 * @date 2022-05-15 修复 bug:处理负数的情况 */ function addNumbers(a, b) { return a + b; }
在上述示例中,我们使用自定义的 @date
标签来记录代码的日期信息。每个标签都包含日期和相应的注释。
使用这种方式,您可以在 JSDoc 注释中记录特定代码片段的创建日期、修改日期或其他相关日期。这样,其他开发人员在查看文档时可以获得更多的上下文信息。
生成文档
我们可以把这个文档注释,生成一个可读的接口文档
demo1.js
/** * 函数防抖 * @author ISail <370763160@qq.com> * @license MIT * @param {Function} func 防抖的目标函数 * @param {Number} duration 函数执行前等待的时间 * @returns {Function} 返回一个防抖的函数 */ function debounce(func,duration = 1000) { }
demo2.js
/** * 获取指定范围内的随机整数 * @param {number} min 随机数的最小值 * @param {aa} max 随机数的最大值 * @return {aaa} 随机数 * @example * getRange(1, 10); // 获取[1,10]之间的随机数 */ function getRandom(min, max) { }
demo3.js
/** * 网络请求 * @param {object} options 配置对象 * @param {string} options.url 请求地址 * @param {'GET'|'POST'} options.method 请求方法 * @param {object} options.body * @param {object} options.headers */ async function request(options) { }
1. 安装js文档生成工具
全局安装jsdoc Document
npm i -g jsdoc
2. 使用js文档生成工具生成文档
你就可以使用这个jsdoc这个命令了
jsdoc <path>
- - 文件路径
点斜杆./
表示当前目录的所有文件,下面以生成文档的示例。
jsdoc ./
3. 查看生成的效果
首页
debounce 函数
getRandom 函数
request 函数
总结
到此这篇关于JavaScript文档注释深入讲解的文章就介绍到这了,更多相关JS文档注释内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!