@private、@protected、@public 和 @readonly 的区别是什么?
在 JSDoc 中,@private、@protected、@public 和 @readonly 分属两个完全不同的控制维度,且标准性与工具支持差异显著。以下是精准对比:
✅ 核心区别总览表
| 标签 | 控制维度 | 标准性 | 作用 | TS 关键字 | 是否互斥 | 典型场景 |
|---|---|---|---|---|---|---|
@private |
访问权限 | ✅ JSDoc 官方 | 仅当前类内部可访问 | private |
✅ 三者互斥 | 内部实现细节、辅助方法 |
@protected |
访问权限 | ✅ JSDoc 官方 | 当前类 + 子类可访问 | protected |
✅ 三者互斥 | 供子类扩展的钩子、共享状态 |
@public |
访问权限 | ✅ JSDoc 官方 | 所有作用域可访问 | public(默认) |
✅ 三者互斥 | 显式覆盖继承的访问级别(罕见) |
@readonly |
可变性 | ❌ 非 JSDoc 标准✅ TypeDoc/TS 扩展 | 初始化后不可重新赋值 | readonly |
❌ 可与前三者任意组合 | 配置项、ID、常量引用 |
🔑 关键认知:
@private/@protected/@public→ “谁能看”(访问控制)@readonly→ “能不能改”(状态控制)@public通常冗余(未标注即默认公开)
🔍 深度解析与避坑指南
1️⃣ 访问权限三标签(互斥,三选一)
class Engine {
/**
* 内部缓存(仅本类可见)
* @private
*/
_cache = {};
/**
* 子类可重写的初始化逻辑
* @protected
*/
_init() { }
/**
* 公开 API(无需 @public!)
* (默认即为 public)
*/
start() { }
}
- ✅
@public使用场景极少:
仅当父类成员被标记为@protected,子类需显式提升为公开时使用(部分工具支持):class Base { /** @protected */ config = {}; } class PublicAPI extends Base { /** @public */ // 覆盖为公开(依赖工具支持) config; } - ⚠️ 默认即公开:未加任何访问标签 =
@public,无需显式标注(写@public属冗余)
2️⃣ @readonly(独立维度,可叠加)
class User {
/**
* 用户ID(子类可读,全局不可改)
* @protected
* @readonly
*/
protected readonly id: string;
/**
* 公开版本号(所有人可读,不可改)
* @readonly
*/
readonly version = '1.0';
}
- ✅ 可与任意访问标签组合(
@private @readonly/@protected @readonly) - ❌ 不控制访问范围:
@readonly成员若为public,外部仍可读取(仅禁止修改) - ❌ 非深度只读:仅阻止重新赋值,不阻止修改对象内部属性(需配合
Object.freeze或 TSReadonly<T>)
🚫 常见误区澄清
| 误区 | 正确理解 |
|---|---|
“@readonly 是访问权限标签” |
❌ 它只控制可变性,与“谁能看到”无关 |
“必须写 @public 表示公开” |
❌ 冗余!未标注即默认公开(JSDoc 规范) |
“@readonly 能深度冻结对象” |
❌ 仅防重新赋值,obj.prop = x 仍可修改(若 prop 非 readonly) |
“标准 JSDoc 工具支持 @readonly" |
❌ jsdoc CLI 会忽略它;仅 VS Code/TypeDoc/TS 识别 |
“@public 可覆盖父类 @private" |
❌ 访问级别不能提升(子类无法将父类 private 变为 public) |
🛠 工具行为对比
| 工具 | @private |
@protected |
@public |
@readonly |
|---|---|---|---|---|
| TypeScript 编译器 | 用 private 强制 |
用 protected 强制 |
默认行为 | 用 readonly 强制 |
| VS Code 智能提示 | 外部访问标黄 | 子类外访问标黄 | 无特殊标记 | 赋值操作标红 |
| TypeDoc / VitePress | 默认不生成文档 | 生成并标注 "Protected" | 生成(无需标签) | 标注 "Readonly" |
| 标准 JSDoc (CLI) | 隐藏 | 标注 | 无影响 | 完全忽略 |
💡 TypeDoc 默认隐藏
@private成员(需--excludePrivate false显式显示)
✅ 最佳实践指南
| 项目类型 | 推荐做法 |
|---|---|
| TypeScript | ✅ 直接用关键字:private readonly id❌ 无需 JSDoc 访问/readonly 标签 |
| 纯 JavaScript (.js) | ✅ 仅当工具需要时添加:/** @protected @readonly */⚠️ 确认文档工具支持(如 TypeDoc) |
| 文档注释 | ✅ 专注写清晰描述:/** 用户唯一ID(子类可读,初始化后不可变) */❌ 避免堆砌冗余标签(如 @public) |
🌟 终极口诀
🔒
@private:“此物藏于密室,仅我可见”
👨👦@protected:“此物存于家祠,子女可瞻仰”
🌍@public:“此物陈列厅堂”(默认如此,无需挂牌)
🚫@readonly:“覆以琉璃罩——可观而不可触”(可置于密室/家祠/厅堂任一处)💡 记住:
- 访问权限三选一(private/protected/public)
@readonly是独立开关,可叠加在任一访问级别上- 现代 TS 项目:忘掉这些 JSDoc 标签,用语言关键字!

浙公网安备 33010602011771号