私有字段(#field)是语言级封装契约,用于保护破坏类不变量的内部状态,需搭配公有接口和私有方法形成逻辑闭环,避免滥用或误用。

私有字段(#field)不是“隐藏起来就完事”的语法糖,而是语言级的封装契约。它的价值不在表面隔离,而在强制约束协作边界、提升运行时确定性——用得好,代码更健壮;滥用或误解,反而增加维护负担。
明确用途:只保护真正不该被外部触碰的内部状态
私有字段适合存放那些一旦被绕过校验直接修改,就会破坏类不变量的数据:
- 缓存计算结果(如
#cachedTotal),避免重复运算 - 临时中间值(如
#debounceTimer、#rawInput),生命周期与类强绑定 - 敏感状态标记(如
#isProcessing、#isValidated),需配合方法原子更新 - 事务日志或审计痕迹(如
#transactionLog),外部不可清空或伪造
别把所有字段都私有化。比如配置项(#apiEndpoint)若需运行时切换,应通过 setter 或构造参数注入,而非硬编码为私有字段。
搭配公有接口:所有对外暴露必须经过受控通道
私有字段本身不提供任何访问能力,必须配对设计清晰的公有方法或 getter/setter:
- 读取敏感值用
getBalance()而非开放#balance - 修改状态用
deposit(amount)内部做校验后更新this.#balance - 需要只读暴露时,getter 可返回副本(如
getItems() { return [...this.#items]; }),防止外部篡改原数组
避免写 get#rawValue() 这类“伪私有”包装——它没增加安全性,只徒增调用层级。
协同私有方法:把校验、转换、副作用收进黑盒
私有字段天然和私有方法(#normalize()、#validate()、#persist())组成逻辑闭环:
-
submit()公有方法里调用this.#validate() → this.#normalize() → this.#persist() - 每个私有方法只处理单一职责,不暴露中间态,也不依赖外部传入的“已校验数据”
- 避免在公有方法里重复写
if (this.#isValid) {...}—— 把判断逻辑下沉到#checkReady()
这样既降低公有 API 的复杂度,也防止使用者因不了解内部依赖而误调顺序。
避开常见误区:不是越私有越安全
私有字段有明确边界,误用会适得其反:
- 子类无法继承访问
#field,若需“受保护”语义,仍要用命名约定(如_internalCount)+ 文档说明 - 不能动态添加(
obj.#dynamic = 1语法错误),所有字段必须在类体中显式声明 - 不要用它替代参数校验——函数入参该检查的,依然要在入口处做,而不是指望调用方“自觉不传坏数据”
- 测试时无需反射或 hack 访问私有字段;真正需要测的是公有行为是否符合预期,比如
account.deposit(-100)是否抛错











