关键是从构造源头控制创建资格,new.target是JS中唯一能在实例化首毫秒识别真实调用者的机制;PaymentFlow基类constructor首行检查new.target===PaymentFlow并报错,子类自动获得安全迭代能力,多层继承中new.target始终指向最外层类,支持运行时策略分流与可信链校验。

要确保支付迭代流不被绕过、不被误用,关键不是“封装数据”,而是从构造源头控制谁有资格创建这个流程。new.target 正是 JavaScript 中唯一能在实例化第一毫秒就识别“真实调用者”的机制。
禁止直接 new PaymentFlow
支付迭代基类本身不持有具体订单或金额,它只定义迭代契约。若被直接 new,说明业务逻辑已失控:
- 在 constructor 首行检查 new.target === PaymentFlow,为真则立即 throw 错误,提示“请继承并实现 #fetchNextStep()”
- 不依赖 this 或 instanceof —— 因为 super() 前 this 不可用,而 new.target 在函数入口就已确定
- 错误信息需具业务语义,例如:“支付流程不可直连,请通过 OrderProcessor 或 RefundHandler 继承使用”
子类自动获得安全迭代能力
所有合法子类(如 CreditCardFlow、AlipayFlow)只需专注业务逻辑,无需重复绑定 Symbol.iterator:
- 基类 constructor 末尾执行 this[Symbol.iterator] = this.#safeIterator.bind(this)
- #safeIterator 内部严格调用子类必须实现的 #fetchNextStep(),该方法可含风控校验、幂等检查、token 验证等
- 若子类自己定义了 Symbol.iterator,new.target 检查不会覆盖它——基类只在未定义时注入,兼容已有逻辑
多层继承中精准识别最终执行者
支付流程常嵌套在组合类中(如 BatchRefundFlow extends RefundFlow),new.target 能穿透整个 super() 链,始终指向最外层被 new 的类:
- 在 PaymentFlow 构造器里打印 new.target.name,得到的是 BatchRefundFlow,而非 RefundFlow 或 PaymentFlow
- 可据此做运行时策略分流:对 BatchRefundFlow 自动启用批量签名,对 AlipayFlow 强制走沙箱环境
- 即便混入(mixin)了日志或监控模块,只要 mixin 不重写 constructor,new.target 仍指向原始子类,保障行为一致
拦截非法构造与第三方注入
防止黑盒插件或调试脚本绕过业务约束,直接 new 出 PaymentFlow 实例:
- 配合私有 Symbol 标记(如 Symbol.for('pay:trusted')),要求子类在 static 初始化时显式注册可信身份
- 构造时检查 new.target[Symbol.for('pay:trusted')] 是否存在且为 true,否则拒绝实例化
- 该标记无法被外部反射读取或伪造,仅你自己的构建流程能注入,形成可信链起点

















