es6 class 无原生私有字段(es2022起支持#),可用约定、闭包、symbol或weakmap模拟;继承通过extends+super()实现;#私有成员仅类内可访问,weakmap利用对象键隔离私有数据,extends要求子类constructor中先调用super()。

ES6 的 class 本身不提供原生的私有字段语法(直到 ES2022 才引入 # 私有字段),但可通过约定、闭包、Symbol 或 WeakMap 实现封装;继承则通过 extends + super() 实现,语义清晰且符合面向对象习惯。
用 # 号实现真正私有成员(ES2022+)
现代 JavaScript 支持以 # 开头的私有字段和方法,它们仅在类内部可访问,外部无法读写或继承:
- 私有字段必须在类体顶层声明(如
#name = 'Alice'),不能动态添加 - 私有方法同样用
#前缀定义,可在其他实例方法中调用 - 子类无法访问父类的私有成员,哪怕重写同名方法也不会覆盖父类私有逻辑
class Person {
#name;
constructor(name) {
this.#name = name;
}
getName() {
return this.#name; // ✅ 允许
}
#greet() {
return `Hello, ${this.#name}`;
}
}
<p>const p = new Person('Bob');
console.log(p.getName()); // "Bob"
console.log(p.#name); // ❌ SyntaxError</p>
用 WeakMap 模拟私有数据(兼容旧环境)
在不支持 # 的环境中,常用 WeakMap 存储实例私有数据,利用键必须是对象的特性实现隔离:
- 每个实例作为 WeakMap 的 key,对应一个私有数据对象
- WeakMap 不阻止垃圾回收,避免内存泄漏
- 外部无法拿到该 WeakMap,也就无法访问私有状态
const privateData = new WeakMap();
<p>class BankAccount {
constructor(balance) {
privateData.set(this, { balance });
}
getBalance() {
return privateData.get(this).balance;
}
deposit(amount) {
privateData.get(this).balance += amount;
}
}</p>
用 extends 和 super 实现继承
extends 声明子类,super() 必须在子类构造函数中调用(且在使用 this 前),用于初始化父类的 this 上下文:
- 子类可复用父类方法,也可用
super.methodName()显式调用父类版本 - 静态方法和 getter/setter 同样可被继承和重写
- 子类构造函数若无
constructor,会自动生成并调用super(...args)
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound.`);
}
}
<p>class Dog extends Animal {
constructor(name, breed) {
super(name); // ✅ 必须先调用
this.breed = breed;
}
speak() {
console.log(<code>${this.name} barks!</code>);
}
info() {
console.log(<code>${this.name} is a ${this.breed}</code>);
}
}</p>
封装与继承结合的实用建议
真正健壮的类设计需兼顾封装意图与继承友好性:
- 把核心逻辑放在私有方法里,暴露的公共方法只做参数校验和流程协调
- 若希望子类能扩展某行为,可提供受保护的钩子方法(如
_onInit()),并约定不直接调用 - 避免在父类构造函数中调用可能被子类重写的方法(易引发未初始化问题)
- 私有字段 + public getter 是控制读写权限的常见组合(如只读 ID、可写但带校验的 name)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











