javascript 中的类私有字段通过在属性名前添加 # 符号来定义,这种字段在类的外部是完全不可访问的,任何尝试读取或写入的操作都会直接抛出 syntaxerror。这意味着你无法通过点语法(如 obj.#field)或方括号语法(如 obj['#field'])来获取这些值,从而实现了真正的封装。

私有字段与普通公有字段的访问差异是什么
普通公有字段存储在实例对象上,可以通过标准的属性访问方式获取,而私有字段则被引擎隐藏,外部代码根本看不到它们的存在。这种设计确保了内部状态不会被意外修改,同时也避免了命名冲突。我们可以通过一个简单的对比程序来观察这两种字段在实例化后的表现。

class Counter {
// 公有字段
count = 0;
// 私有字段
#secret = 42;
constructor() {
this.count++;
}
getSecret() {
return this.#secret;
}
}
const c = new Counter();
console.log(c.count); // 输出: 1
console.log(c.getSecret()); // 输出: 42
console.log(c.#secret); // SyntaxError: Private field '#secret' must be defined in a class but overridden with 'setter' is not allowed运行上述代码,c.count 正常返回 1,c.getSecret() 正常返回 42。但是,如果尝试在类外部直接访问 c.#secret,控制台会立即报错。这证明了私有字段不仅在逻辑上被保护,而且在语法层面就被禁止了外部访问。相比之下,count 作为公有字段,其值直接暴露在对象原型链之外的实例属性中。
立即学习“Java免费学习笔记(深入)”;
为什么私有字段不能通过反射 API 获取
即使使用 Object.keys()、Object.getOwnPropertyNames() 或 Reflect.ownKeys() 等标准反射 API,也无法列出或获取私有字段的名称。这是因为私有字段不属于对象的常规属性集合,它们在 V8 等 JavaScript 引擎中有独立的存储机制。以下代码展示了这些 API 对私有字段的“视而不见”。

class DataStore {
#internalData = { value: 100 };
publicData = { value: 50 };
}
const store = new DataStore();
console.log(Object.keys(store)); // ['publicData']
console.log(Object.getOwnPropertyNames(store)); // ['publicData']
console.log(Reflect.ownKeys(store)); // ['publicData']
// 尝试直接访问私有字段
try {
console.log(store['#internalData']);
} catch (e) {
console.log('Error:', e.message);
}执行结果显示,所有反射 API 都只返回了 publicData,完全忽略了 #internalData。同时,直接使用字符串键名 '#internalData' 访问也会失败,因为引擎不会将字符串解析为私有标识符。这种机制防止了通过元编程手段绕过封装,确保了数据的安全性。
私有字段在继承时如何影响子类访问
私有字段是绑定到具体类的,子类无法直接访问父类的私有字段,即使子类继承了父类的方法。这是因为私有字段的可见性范围仅限于定义它的类块内部。如果子类需要访问父类的私有状态,必须通过父类提供的公共方法或受保护的方法(通常以 _ 开头,但这只是约定而非语言特性)来间接获取。
class Parent {
#privateValue = 'hidden';
getValue() {
return this.#privateValue;
}
}
class Child extends Parent {
testAccess() {
// console.log(this.#privateValue); // SyntaxError: Private field '#privateValue' must be defined in a class but overridden with 'setter' is not allowed
return this.getValue(); // 正确:通过父类方法访问
}
}
const child = new Child();
console.log(child.testAccess()); // 输出: hidden在上述代码中,Child 类试图直接访问 this.#privateValue 会导致语法错误,因为 #privateValue 是在 Parent 中定义的。然而,Child 可以调用 getValue(),该方法在 Parent 的作用域内执行,因此有权访问该私有字段。这种设计保证了父类的内部实现细节不会泄露给子类,同时允许子类通过受控接口与父类状态交互。


















