可通过object.defineproperties在原型上定义get/set访问器,结合weakmap存储私有状态并嵌入权限逻辑,实现属性级访问控制;访问器默认不可枚举不可配置,配合object.freeze可保障权限模型稳定。

可以利用 Object.defineProperties 在原型对象上定义带有 get / set 的访问器属性,结合闭包或 WeakMap 存储私有状态,实现属性级的访问权限控制——关键在于把“权限逻辑”写进访问器内部,而非依赖属性本身的可枚举性或可配置性。
在原型上定义受控访问器属性
直接在原型对象上调用 Object.defineProperties,为每个需管控的属性声明 get 和(可选)set。此时访问器函数能访问到实例上下文(this),可用于判断当前操作是否被允许。
- 避免在访问器中直接读写同名自有属性(会触发无限递归),改用
Object.prototype.hasOwnProperty.call(this, 'prop')或 Symbol/WeakMap 存储真实值 - 访问器默认不可枚举、不可配置,天然适合封装敏感字段
- 权限判断可基于 this.constructor、角色标识、调用栈(谨慎)、或外部策略函数
用 WeakMap 隔离私有状态与权限边界
将实际数据存入 WeakMap,键为实例对象,值为私有数据对象。这样既避免污染实例自身属性,又确保子类实例无法绕过原型访问器直接读取。
- WeakMap 实例通常定义在闭包内,仅访问器函数能访问,防止外部篡改
- 在
get中检查权限(如this._role === 'admin'),不满足则抛错或返回默认值 -
set中可加入类型校验、范围限制、审计日志等逻辑,不只是赋值
配合 Object.freeze 或 Object.seal 控制原型结构稳定性
定义完访问器后,对原型调用 Object.freeze(Proto.prototype),防止后续意外添加/删除/重定义属性破坏权限模型。
-
freeze确保访问器定义不可被覆盖,但注意它不影响已有访问器内部逻辑的执行 - 若需允许子类扩展,可用
Object.seal替代,保留属性值修改能力但禁止新增/删除 - 不建议在构造函数中对每个实例
freeze,那会彻底禁用所有 setter
继承场景下的权限一致性处理
子类原型链会自然继承父类原型上的访问器,但要注意:如果子类也定义同名属性(尤其使用 Object.defineProperty 覆盖),可能破坏权限逻辑。
- 推荐子类通过
super.prop显式委托,而非重新定义 - 可在父类访问器中检查
this.constructor,对特定子类放宽/收紧规则 - 若需差异化权限,建议用策略模式:将权限判定抽成方法(如
canReadProp()),子类可安全重写










