new.target在class构造器中始终指向实际触发new操作的类,而非定义该构造器的类;例如new dog()时animal父类constructor内new.target为dog而非animal。

类的构造方法(constructor)**天然只能通过 new 调用**,所以 new.target 在 class 内部永远不会是 undefined。但关键不在于“是否被 new 调用”,而在于:它指向谁?这决定了你能否区分“直接实例化本类”还是“被子类继承后间接调用”。
class 中 new.target 的真实含义
new.target 在 constructor 里始终指向**实际触发 new 操作的那个类**,不是写这个 constructor 的类本身。
-
new Animal()→Animal构造器中new.target === Animal -
class Dog extends Animal { constructor() { super() } },再执行new Dog()→Animal构造器中new.target === Dog(不是Animal)
判断是否被直接 new,而非继承调用
如果你想禁止用户写 new Animal(),只允许 new Dog() 这类继承后的使用,就在父类 constructor 开头加一行判断:
if (new.target === Animal) throw new TypeError('Animal 是抽象类,不能直接实例化')- 子类调用
super()时,new.target是子类,条件不成立,不会报错 - 这个检查比
this instanceof Animal更准确——后者在call/apply或代理场景下可能失真
获取终端子类名称或做差异化初始化
利用 new.target.name 可以安全拿到最终被 new 的那个类的名字:
-
console.log('创建了:', new.target.name)在任意层级基类中都输出"Dog"(不是"Animal") - 可用于加载对应配置、选择默认行为、打日志标识等
- 比
this.constructor.name更可靠,不受bind、箭头函数或Proxy干扰
注意边界情况
有些细节容易忽略,但会影响逻辑稳定性:
- 箭头函数没有自己的
new.target,也不能当构造函数用,别在箭头函数里查它 - 类的
constructor内部一定有new.target,无需先判undefined;但普通函数构造器必须先检查,否则this在严格模式下会是undefined - 如果用
Proxy包裹类并重写construct,记得把第三个参数newTarget传给Reflect.construct,否则new.target会丢失











