javascript 自 es2022 起通过 # 前缀支持真正私有成员,仅类内可访问且运行时强制保护;public 成员默认开放但需规范初始化;protected 仅靠 _ 约定与文档提示,无语法保障;static 成员依前缀决定可见性。

JavaScript class 中没有像 Java 那样的 public、protected、private 关键字(原生语法层面),但自 ES2022 起,已通过 # 前缀语法正式支持私有字段和方法,配合约定与工具链,可实现规范、可靠、可维护的访问控制。
用 # 前缀声明真正的私有成员
这是目前唯一被语言标准认可、运行时强制执行的私有机制:
-
必须以 # 开头,如
#id、#validate(),否则报SyntaxError - 只能在类体内部声明,不能动态添加或在外部补定义
- 类内所有方法(包括 getter/setter、static 方法)均可自由访问
this.#xxx - 子类无法访问父类的
#xxx,哪怕继承了该类也不行——这是硬性隔离,不是约定 - 外部任何访问(
obj.#xxx、Reflect.get(obj, '#xxx')、obj['#xxx'])均抛错
public 成员靠默认行为 + 显式设计
不加前缀的属性和方法,默认就是 public 的,但需注意实践规范:
- 实例属性建议在 constructor 中初始化,避免隐式挂载;不推荐在原型上直接赋值实例状态
- 方法尽量写在 class body 内(而非 prototype),保证 this 绑定清晰、便于调试
- 若需暴露只读状态,用
get xxx()定义 getter,避免直接暴露可变字段 - 对外提供能力,优先封装为方法而非开放内部字段——比如用
reset()代替暴露this.#count = 0
模拟 protected:靠命名约定 + 文档约束
JavaScript 标准中没有 protected 语义,但可通过团队协作方式近似实现:
- 使用
_前缀(如_internalId、_onUpdate)作为“受保护成员”约定,表示“仅子类应调用,不对外承诺兼容” - 配合 JSDoc 标注
@protected,TypeScript 可据此做检查(需开启noImplicitAny和checkJs等) - 子类中调用时,仍走 public 路径,不享受语法保护——所以关键逻辑仍应放在私有方法里,
_成员只作钩子或委托入口 - 避免把真正敏感的状态放在
_字段里,它只是协作提示,不是安全边界
static 成员的可见性管理
静态成员属于类本身,其访问权限由两层决定:声明位置 + 前缀
-
static #name:私有静态字段/方法,仅本类内部可用,子类不可见 -
static name:公共静态成员,可通过Class.name访问,等同于模块级导出 - 不建议用
this.constructor.xxx动态访问静态成员,语义模糊且不利于 tree-shaking - 工具链(如 TypeScript)支持
static readonly或私有静态字段,进一步收窄意图
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











