new.target 是 javascript 中用于识别构造函数调用上下文的元属性,可辅助实现运行时防御,但无法真正阻止恶意实例化;它通过抛错或拒绝非预期调用(如直接实例化抽象基类、校验可信子类、检测环境异常)来使非法实例失效,是纵深防御的一环而非银弹。

new.target 是 JavaScript 中一个原生的元属性,它在函数或构造函数执行时指向当前被 new 调用的构造函数本身。它不是用来“阻止”实例化,而是提供一种运行时识别调用上下文的能力——关键在于:能否区分“合法调用”和“第三方插件擅自 new”的行为。
但必须先说清楚一个现实前提:new.target 无法真正“防止”恶意实例化。只要第三方插件能拿到你的构造函数引用(比如通过全局变量、模块导出、原型链遍历),它就能 new YourComponent(),而 JS 引擎不会报错,new.target 也照常返回那个构造函数。它不拦截,只反映事实。
它的价值,在于让你在构造函数内部主动拒绝非预期的调用方式,从而让恶意实例“创建失败”或“立即失效”,而不是静默运行、污染状态或泄露敏感逻辑。
✅ 明确合法调用边界:只允许子类继承,禁止直接 new
很多公共组件(如 UI 框架中的 BaseModal、FormController)本意是被继承扩展,而非直接实例化。这时可用 new.target === YourClass 做守门人:
class BaseWidget {
constructor() {
if (new.target === BaseWidget) {
throw new Error('BaseWidget is abstract: extend it, don’t instantiate directly');
}
// 正常初始化逻辑
}
}
第三方插件若写 new BaseWidget(),会立刻抛错;只有 class MyWidget extends BaseWidget 才能通过。
⚠️ 注意:这防不住
Reflect.construct(BaseWidget, [])或Function.prototype.bind.call(BaseWidget)等绕过方式,但已覆盖 95% 的粗放式插件注入。
✅ 绑定可信调用来源:校验 new.target 是否来自你控制的命名空间
如果组件必须可实例化,但只允许在你自己的模块/包内创建(例如 @myorg/ui 下的 Button),可结合模块标识做轻量白名单:
// 假设你在构建时注入一个唯一标记
const MY_ORG_CONSTRUCTOR_KEY = Symbol.for('myorg:widget:trusted');
class Button {
constructor() {
// 检查 new.target 是否带有可信标记(仅你自己的子类才可能设置)
const targetProto = Object.getPrototypeOf(new.target);
if (!targetProto || !targetProto[MY_ORG_CONSTRUCTOR_KEY]) {
console.warn('[Button] Unauthorized instantiation detected — blocked');
throw new SecurityError('Button may only be instantiated by trusted subclasses');
}
}
}
// 你自己的子类显式声明可信
class TrustedButton extends Button {
constructor() {
super();
}
}
Object.defineProperty(TrustedButton.prototype, MY_ORG_CONSTRUCTOR_KEY, { value: true });
第三方插件即使 new Button(),因 new.target.prototype 没有该 symbol,直接被拒。
✅ 配合 new.target 做运行时环境指纹(辅助判断)
单独用 new.target 不够,但结合其他上下文可增强判断力。例如检测是否在沙箱 iframe、是否被 Proxy 包裹、是否处于非标准 global:
class SecurePanel {
constructor() {
// 1. 检查是否被非预期的 Proxy 构造(常见于插件劫持)
if (typeof new.target === 'function' &&
new.target.toString().includes('[native code]') === false &&
new.target.name === 'SecurePanel') {
throw new Error('SecurePanel constructor has been proxied — blocked for integrity');
}
// 2. 检查 global 是否被篡改(插件常污染 window)
if (globalThis !== window || window.constructor !== Window) {
throw new Error('Running in compromised global context');
}
}
}
这类检查不绝对可靠,但能筛掉大量低级插件注入。
❌ 它防不住什么?(务必清醒)
- 插件通过
eval、Function()动态构造同名类并new - 插件劫持
window.YourClass后再new window.YourClass() - 插件使用
document.createElement('your-component')绕过 JS 构造函数 - 插件在 Shadow DOM 内部或 sandbox iframe 中新建实例(
new.target仍有效,但隔离已生效)
所以 new.target 是纵深防御中的一环,不是银弹。它最适合配合以下手段:
- Shadow DOM 封装组件实现(物理隔离样式与 DOM)
-
CSP 限制
unsafe-eval和内联脚本(切断动态构造路径) -
模块加载时立即冻结构造函数(
Object.freeze(MyClass)+Object.seal(MyClass.prototype))
不复杂但容易忽略。










