安全类构建器的核心是工厂函数作为唯一可信装配点,统一校验、创建、设原型、注入属性;原型须预定义冻结,用reflect.setprototypeof替代__proto__,配合object.freeze与preventextensions实现双保险防护。

用 Reflect.setPrototypeOf 与工厂函数结合构建类构建器,核心不是“强行改原型”,而是让工厂函数成为可控的装配入口,把原型设置动作收束在可信、可审计、有兜底的环节中。真正安全的关键,是切断不可信数据流、明确控制权边界、避免运行时动态污染。
工厂函数作为唯一可信装配点
所有实例创建必须经过工厂函数,禁止直接 new 或 Object.create 后裸调 setPrototypeOf。工厂内部统一处理:校验参数 → 创建干净对象 → 设置可信原型 → 注入专属属性。
- 用
Object.create(null)初始化空对象,彻底规避__proto__污染风险 - 原型对象必须是预定义常量(如
const UserProto = { ... }),不从用户输入或配置中动态生成 - 调用
Reflect.setPrototypeOf(obj, UserProto)前,检查obj是否可扩展、UserProto是否为对象或 null
用 Reflect.setPrototypeOf 替代 __proto__ 赋值
__proto__ 是非标准遗留属性,行为不稳定;Reflect.setPrototypeOf 提供标准化接口,并返回布尔结果,便于失败判断和日志记录。
- 成功时返回
true,可继续注入属性;失败时返回false,立即抛错或降级处理 - 严格模式下失败会抛
TypeError,比静默忽略更利于早期发现问题 - 避免对冻结对象(
Object.freeze())调用,工厂函数应提前检查Object.isFrozen(obj)
原型链冻结 + 运行时防护双保险
仅靠一次 setPrototypeOf 不足以保证长期安全。需配合基础防护机制,防止后续意外篡改。
- 应用初始化后执行
Object.freeze(Object.prototype),阻断对基础原型的任何修改 - 关键原型对象(如
UserProto)也应调用Object.freeze(),禁止增删方法 - 工厂函数返回前,可用
Object.preventExtensions(obj)锁定实例结构,防止后期乱加字段
支持策略切换但不牺牲可预测性
若需根据条件使用不同原型(如 AdminProto / GuestProto),应在工厂内通过白名单映射,而非接收外部传入的原型对象。
- 定义策略表:
const PROTO_MAP = { admin: AdminProto, guest: GuestProto } - 工厂只接受字符串标识符:
createUser({ role: 'admin', name }) - 内部查表取原型,杜绝任意对象注入,避免原型劫持











