

新闻资讯
技术学院闭包是模拟私有变量最稳妥的方式,因其兼容性好、数据真正不可见;#field 是语法级私有但仅限类内;WeakMap 和 Symbol 均非真正私有,仅作隐藏或折中方案。
JavaScript 原生不支持 private 关键字(ES2025 起的 #field 是语法级私有,但仅限类字段),所以闭包仍是封装数据最通用、兼容性最好的方式。核心逻辑是:在函数作用域内声明变量,只通过返回的函数暴露有限接口。
function createCounter() {
let count = 0; // 外部无法直接访问
return {
increment() { count++; },
getValue() { return count; }
};
}
const counter = createCounter();
counter.increment();
console.log(counter.getValue()); // 3
// console.log(counter.count); // undefined —— 真正不可见
for (let i...) {} 之外的写法)#field 是目前唯一由语言规范保证的私有机制,但仅作用于 class 内部,且不能动态访问(Reflect.get、in、for...in 都无效)。
class BankAccount {
#balance = 0;
constructor(initial) {
this.#balanc
e = initial;
}
deposit(amount) {
this.#balance += amount;
}
getBalance() {
return this.#balance; // ✅ 可读
}
}
const acc = new BankAccount(100);
acc.deposit(50);
console.log(acc.getBalance()); // 150
// console.log(acc.#balance); // ❌ SyntaxError: Private field '#balance' must be declared in an enclosing class
#field 必须在类体顶层显式声明(不能在方法里 let #x)acc['#' + 'balance'] 不生效#field,哪怕同名也不共享当需要为已有构造函数或原型方法添加私有状态,又不想改结构时,WeakMap 是折中选择:以实例为 key,存储独立数据对象,避免内存泄漏。
const privateData = new WeakMap();
class Logger {
constructor(name) {
privateData.set(this, { name, level: 'info' });
}
getName() {
return privateData.get(this).name;
}
setLevel(level) {
privateData.get(this).level = level;
}
}
privateData.get(this) 前已用 set 初始化,否则返回 undefined
privateData.get(instance) —— 它不是语言级私有,只是“不易发现”Symbol 创建的属性名不会出现在 for...in 或 Object.keys() 中,但可通过 Object.getOwnPropertySymbols() 暴露,属于“隐藏而非禁止”。
const _id = Symbol('id');
class User {
constructor(id) {
this[_id] = id;
}
getId() {
return this[_id];
}
}
const u = new User(123);
console.log(u[_id]); // 123 —— 可直接访问
console.log(Object.getOwnPropertySymbols(u)); // [Symbol(id)]
#field 是唯二能真正隔离数据的方案;WeakMap 和 Symbol 都依赖约定或运行时特性,一旦脱离上下文就失去“私有”意义。选哪种,取决于你是否需要跨浏览器支持、是否接受类语法约束、以及对“私有”的定义到底有多严格。