
要确保敏感的支付组件只能通过 new 实例化,核心是利用 new.target 在构造函数开头做即时拦截——它在普通调用时为 undefined,而 new 调用时指向当前类本身。这不是补丁式校验,而是运行时第一道防线。
在构造函数中强制 new 调用
支付类必须拒绝任何非构造调用,否则 this 可能绑定到全局或 undefined(严格模式下),导致私有状态丢失、凭证泄漏或静默失败:
- 在类的
constructor第一行检查if (!new.target) throw new TypeError('PaymentProcessor 必须用 new 调用') - 该判断必须放在任何属性赋值、密钥加载或外部依赖初始化之前
- 错误类型建议用
TypeError,语义上更准确(调用方式错误,而非逻辑错误)
防止基类被直接实例化
若支付逻辑拆分为抽象基类(如 BasePayment)和具体实现(如 StripeProcessor),可用 new.target 锁死基类不可用:
- 在基类
constructor中写if (new.target === BasePayment) throw new TypeError('BasePayment 是抽象类') - 子类调用
super()时,父类中的new.target仍指向子类,因此检查自然绕过 - 这样既保障了继承结构,又杜绝了绕过具体实现的风险
避免箭头函数破坏检测链
支付类内部若使用箭头函数封装关键方法(如签名生成、token 加密),需注意:new.target 在箭头函数中不可用,它会沿作用域链向上取外层函数的值:
- 不要在箭头函数里做
new.target判断——它无法反映当前执行是否源于new - 所有关键防护逻辑(包括
new.target检查)必须放在普通函数或类构造器内 - 若需在回调中确认上下文,应显式传入或缓存
new.target值(如const ctor = new.target)
配合其他防御手段增强可信度
new.target 是必要但不充分条件。实际部署中还需组合使用:
- 启用严格模式(
'use strict'),让遗漏new的调用直接让this为undefined,触发早期报错 - 在构造完成后,可附加一次运行时验证:比如检查
this是否拥有预期的私有字段(hasOwnProperty('_key')) - 构建时通过 TypeScript 的
abstract类或 ESLint 规则(如no-new配合自定义白名单)提前拦截误用











