最直接有效的方式是在构造函数开头检查 new.target 是否存在。它天然区分调用方式,被 new 调用时指向当前构造函数,普通调用时为 undefined;类中 constructor 必有值;可实现强制 new 调用和抽象基类语义,但不适用于箭头函数和安全敏感场景。

最直接有效的方式就是在构造函数开头检查 new.target 是否存在。它天然区分调用方式,不依赖 this 绑定或外部环境,是 ES6 提供的官方解决方案。
核心判断逻辑:只认 new,不认其他
new.target 在函数体内始终可靠:
- 被
new调用时(包括new MyClass()或Reflect.construct()),new.target指向当前构造函数本身 - 被普通调用(
MyClass())、call/apply、或箭头函数中访问时,值为undefined - 类的
constructor中必定有值,不会为undefined(因为类强制 require new)
标准防护写法(推荐)
在函数体第一行做拦截,简洁明确:
function User(name, email) {
if (!new.target) {
throw new TypeError('User 必须使用 new 调用');
}
this.name = name;
this.email = email;
}
这样 User('Alice', 'a@b.com') 立即报错;new User('Alice', 'a@b.com') 正常执行。无需处理 this 是否为实例,也不怕 call/apply 伪造 —— 因为它们无法伪造 new.target。
配合类实现抽象基类语义
利用 new.target 在继承链中的精确指向,可禁止基类被直接实例化:
class Repository {
constructor() {
if (new.target === Repository) {
throw new TypeError('Repository 是抽象类,不可直接 new');
}
}
}
class UserRepository extends Repository {
constructor() {
super();
console.log('UserRepository 实例创建成功');
}
}
new Repository() 报错;new UserRepository() 成功 —— 这种控制粒度是 this instanceof 完全做不到的。
注意边界与限制
虽然强大,但需清楚它的适用范围:
- 仅在普通函数和 class 构造器中可用;箭头函数无自有
new.target,且不能作为构造函数 - 不适用于安全敏感场景(如权限校验),因为它只是运行时提示,无法阻止恶意代码绕过
- 动态生成的函数(如
Function('return this'))中行为一致,但极少需要在此类场景下检测

















