new.target 是拦截非法构造调用的核心机制,可提前阻止非 new 调用、禁止基类直连实例化、校验子类初始化完整性,并确保 Proxy construct 正确传递原型链。

直接用 new.target 拦住错误调用,就能避免因漏写 new 或误当普通函数调用导致的 this 错乱、undefined 赋值、静默失败等崩溃问题。核心不是“补救”,而是“提前拦截”。
阻止非构造调用:第一道防线
在构造函数开头检查 new.target 是否存在,是最简单也最有效的防御。
if (!new.target) throw new TypeError('MyClass 必须用 new 调用')- 这能立刻捕获
MyClass()、MyClass.call(obj)、MyClass.apply(null)等所有非new场景 - 严格模式下,普通调用时
this是undefined,赋值会直接报错;非严格模式下指向全局对象,隐患更大——new.target判断不依赖this,更可靠
禁止基类直连实例化:模拟抽象类
若某个类只应被继承、不该被 new,就用 new.target === MyClass 做身份锁定。
class Animal { constructor() { if (new.target === Animal) throw new Error('Animal 不可直接实例化') } }- 子类
new Dog()时,new.target是Dog,条件不成立,放行 - 比靠文档或约定更硬性,运行时即拦截,避免“基类被误用后逻辑错乱”的深层崩溃
统一校验子类初始化完整性
仅防误调还不够,还要确保子类真正完成了该做的事。靠 new.target 区分调用者后,再加一层契约检查。
- 要求子类必须定义静态属性
requiresInit = true,父类构造中检查:if (new.target !== Parent && !new.target.requiresInit) throw … - 或强制子类实现实例方法
init(),父类末尾调用:if (typeof this.init !== 'function') throw … - 这样就把“子类忘记初始化关键字段”这类隐性崩溃,提前暴露为明确报错
避免 Proxy construct 陷阱破坏原型链
若用 Proxy 拦截构造过程(比如日志、埋点),必须正确传递 new.target,否则 instanceof 失效、方法找不到、继承断裂——这些全是运行时崩溃温床。
- 错误写法:
return new _class(...args)→ 实例原型变成_class.prototype,丢失子类链 - 正确写法:
return Reflect.construct(_class, args, newTarget)→ 显式指定原型目标,保持new Child() instanceof Child为true - 只要用了
Proxy包裹可被继承的类,这条就是必守底线










