Symbol实现约定式私有:属性不可枚举、不被for...in遍历、不被JSON.stringify包含,但可通过Object.getOwnPropertySymbols()等访问;需结合闭包或#私有字段保障安全。

Symbol 可以作为对象的属性名来模拟私有属性,但需注意:它并非真正私有(仍可通过 Object.getOwnPropertySymbols() 或 Reflect.ownKeys() 访问),而是“不被枚举、不会被 for...in 遍历、不被 JSON.stringify 包含”,从而实现一种**约定式私有**。
用 Symbol 创建唯一属性名
每次调用 Symbol() 都返回一个全新、唯一、不可复现的值,适合避免属性名冲突:
-
const _id = Symbol('id');—— 描述字符串仅用于调试,不影响唯一性 -
const user = { [_id]: 123 };—— 方括号语法写入 Symbol 属性 -
user[_id]可正常读写,但user.id或user['id']无法访问
封装私有数据(推荐配合闭包)
单独用 Symbol 不足以隐藏数据;更稳妥的方式是结合闭包,把 Symbol 和数据都封在函数作用域内:
function createUser(name) {
const _name = Symbol('name');
return {
setName(value) {
this[_name] = value;
},
getName() {
return this[_name];
}
};
}
const u = createUser();
u.setName('Alice');
console.log(u.getName()); // 'Alice'
console.log(u._name); // undefined(属性名是 Symbol,不是字符串'_name')
console.log(u[Symbol('name')]); // undefined(每次 Symbol() 都是新值)
限制外部访问的实用技巧
若希望进一步降低误访问概率,可统一管理 Symbol 实例:
- 将 Symbol 存在模块顶层或 WeakMap 中,避免重复创建
- 使用
Symbol.for('key')创建全局注册的 Symbol(慎用,会跨模块共享) - 搭配
Object.defineProperty设置enumerable: false(Symbol 属性默认就是不可枚举) - 避免在公开 API 中暴露 Symbol 常量;如必须导出,用
Symbol('mylib.private')并注明“仅供内部使用”
注意 Symbol 属性的可见性边界
Symbol 属性不是绝对隐藏,开发者仍可通过以下方式发现:
-
Object.getOwnPropertySymbols(obj)—— 获取所有 Symbol 键 -
Reflect.ownKeys(obj)—— 同时返回字符串键和 Symbol 键 - Chrome/Firefox 控制台会显示 Symbol 属性(带 @@ 标记)
因此,Symbol 更适用于“防止意外覆盖/遍历”,而非安全敏感场景(如密码、密钥等应存在闭包或 # 私有字段中)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











