JS中无法用private关键字,但可通过闭包实现真正私有变量:在构造函数内用let/const定义变量,并将访问它的方法定义在同一作用域内赋给this;ES2022起支持#私有字段语法。

JS 构造函数中无法像 Java 那样用 private 关键字声明私有变量,但可以通过闭包 + 作用域隔离实现真正意义上的私有变量和信息隐藏——外部无法直接访问,只能通过公开方法间接操作。
利用闭包在构造函数内创建私有状态
在构造函数内部定义变量(let 或 const),并让所有需要访问它的方法(包括原型方法)都定义在同一个作用域内(即作为闭包函数返回或绑定)。这样变量就“被封闭”在该作用域中,外部不可见。
常见写法是:不使用 prototype,而是在构造函数里直接给 this 赋值为闭包函数:
- 私有变量定义在构造函数作用域内(如
let balance = 100;) - 所有需访问它的方法(如
deposit、getBalance)都在同一作用域中定义,并捕获该变量 - 这些方法被赋给
this,成为实例的“公有接口”
示例:
function BankAccount(initial) {
let balance = initial; // ✅ 私有变量,外部无法访问
this.deposit = function(amount) {
if (amount > 0) balance += amount;
};
this.withdraw = function(amount) {
if (amount > 0 && amount <= balance) balance -= amount;
};
this.getBalance = function() {
return balance; // ✅ 只能通过此方法读取
};
}
const acc = new BankAccount(500);
console.log(acc.balance); // undefined —— 不可访问
console.log(acc.getBalance()); // 500 —— 正确访问方式
结合 class 语法(ES6+)的私有字段方案
现代 JS(ES2022+)支持真正的私有字段语法:#name 开头的属性。它不是闭包模拟,而是语言级私有机制,必须在 class 内部声明,且只能被 class 中定义的方法访问。
- 私有字段必须用
#前缀,且需在类体顶层显式声明(推荐用constructor或字段声明语法) - 不能在 class 外读写,连
in、hasOwnProperty、JSON.stringify都不可见 - 注意:私有方法也需以
#开头,且只能被同 class 内其他方法调用
示例:
class BankAccount {
#balance; // ✅ 私有字段声明(可选,但推荐)
constructor(initial) {
this.#balance = initial;
}
deposit(amount) {
if (amount > 0) this.#balance += amount;
}
#validateWithdraw(amount) { // ✅ 私有方法
return amount > 0 && amount <= this.#balance;
}
withdraw(amount) {
if (this.#validateWithdraw(amount)) {
this.#balance -= amount;
}
}
getBalance() {
return this.#balance;
}
}
避免常见误区
-
不要用下划线命名(如
_balance)假装私有:这只是约定,完全可被外部随意修改,不提供任何保护 -
避免把方法挂到
prototype却依赖闭包私有变量:原型方法无法访问构造函数内的let变量,会报错或读到undefined -
私有字段
#不能动态计算名:不支持this[#key]或this[`${prefix}balance`],必须字面量写死 -
私有字段不可继承:子类无法访问父类的
#field,哪怕重写方法也不行
选型建议
新项目优先用 class + # 私有字段:语义清晰、工具友好(TS/IDE 支持好)、性能稳定;老环境或需兼容 IE 等,用闭包模式更稳妥。两种方式都实现了真正的信息隐藏,关键在于变量生命周期与访问权限是否被严格约束在可控边界内。


















