在 javascript 中,class 语法本身并不直接提供模块模式(module pattern)的私有变量机制,因为 class 字段默认都是公开的。要实现类似传统函数式模块模式的私有状态封装,必须使用 es2022 引入的 # 符号来定义私有字段。通过这种方式,可以在类内部定义以 # 开头的属性,这些属性只能在类的实例方法中访问,外部无法读取或修改,从而实现了真正的数据隐藏和模块化封装。

如何实现带有私有状态的类
实现带有私有状态的类,核心是使用 # 前缀声明字段。在类定义中,任何以 # 开头的标识符都会被引擎视为私有名称(Private Name)。这意味着该字段不会出现在实例的枚举属性中,也无法通过 instance.fieldName 的方式从外部访问。这种机制比传统的闭包更直观,因为它直接绑定在类结构上,同时保持了严格的访问控制。

class BankAccount {
#balance = 0;
constructor(initialDeposit) {
this.#balance += initialDeposit;
}
deposit(amount) {
if (amount > 0) {
this.#balance += amount;
return true;
}
return false;
}
getBalance() {
return this.#balance;
}
}
const account = new BankAccount(100);
account.deposit(50);
console.log(account.getBalance()); // 150
// console.log(account.#balance); // SyntaxError: Private field '#balance' must be declared in an enclosing class
如何处理私有字段的继承与冲突
在处理私有字段的继承时,需要注意每个子类都会获得自己独立的私有命名空间。即使父类和子类定义了同名的 #privateField,它们也是完全不同的两个字段,互不干扰。这种设计避免了传统原型链继承中可能出现的命名冲突问题,但同时也意味着子类不能直接访问父类的私有字段,除非父类提供了公共方法作为中介。如果需要在子类中扩展私有逻辑,应确保子类重新定义所需的私有字段,而不是尝试复用父类的私有状态。

class Parent {
#secret = "Parent Secret";
showSecret() {
console.log(this.#secret);
}
}
class Child extends Parent {
#secret = "Child Secret"; // 这是另一个独立的私有字段
showChildSecret() {
console.log(this.#secret);
}
}
const child = new Child();
child.showSecret(); // "Parent Secret"
child.showChildSecret(); // "Child Secret"
基于程序中某个输入、条件或结果的具体问题
当程序尝试从外部访问私有字段时,会立即抛出 SyntaxError。这是一个编译时的错误,而不是运行时的异常。这意味着开发者在编写代码阶段就会收到明确的反馈,防止了意外暴露内部状态。这种严格性确保了模块模式的封装性不会被破坏,同时也要求开发者在设计类时必须明确区分哪些数据是内部的,哪些是对外暴露的接口。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











