new.target 是 es6 元属性,构造调用时返回构造函数,否则为 undefined;可用于基类中判断合法调用、避免重复初始化、支持 class 继承与原型继承共存。

new.target 是 ES6 引入的元属性,它在函数或构造函数被 new 调用时返回该构造函数本身;若非构造调用(如普通函数调用),则为 undefined。这一特性可被巧妙用于基类设计,尤其在需支持“类式继承”与“旧式原型链继承”共存的场景中——比如你维护一个被大量老代码依赖的基类,又希望新用户能用 class 语法、且不破坏已有 Object.create(OldBase.prototype) 或 util.inherits() 的用法。
判断是否为合法构造调用,拒绝裸调用
很多老基类容易被误写成 MyBase()(漏掉 new),导致 this 指向全局或 undefined,引发静默错误。利用 new.target 可主动拦截:
function MyBase() {
if (!new.target) {
throw new TypeError('MyBase must be called with new');
}
this._initialized = true;
}
这样既保护了实例状态,也向使用者明确契约:必须用 new。注意:箭头函数无 new.target,所以基类必须是普通函数或 class 构造器。
兼容 Object.create 继承链,避免重复初始化
在传统原型继承中,子类常通过 Child.prototype = Object.create(Parent.prototype) 建立原型链,再手动调用 Parent.call(this, ...)。但若基类构造器内部做了不可重复的操作(如绑定事件、初始化私有字段),直接 Parent.call(this) 就可能出问题。
此时可用 new.target 区分「首次构造」和「显式父类调用」:
function MyBase(...args) {
// 只有真正被 new 调用(且是本类,非子类)时才执行核心初始化
if (new.target === MyBase) {
this._uid = Symbol('MyBase');
this._setupInternal();
}
}
MyBase.prototype._setupInternal = function() {
// 实际初始化逻辑(只执行一次)
};
子类继承时,new.target 指向子类构造器,因此基类中不会重复执行 _setupInternal;而若有人手动 MyBase.call(childInstance),因 new.target 为 undefined,也会跳过——双重保险。
支持 class extends 且保留对 super() 的语义一致性
当用户用 class Child extends MyBase 时,super() 内部会确保 new.target 在进入 MyBase 时仍指向 Child(而非 MyBase)。这意味着你可以安全地做「按派生类定制行为」:
function MyBase() {
if (!new.target) throw new TypeError('Must use new');
// 根据实际构造者决定默认配置
const DefaultConfig = new.target === MyBase
? { legacy: true }
: { modern: true };
this.config = Object.assign({}, DefaultConfig, arguments[0]);
}
这样,new MyBase() 得到 legacy 配置,new Child() 却自动获得 modern 配置,无需子类额外传参,也不影响已有 Object.create 方式(因其不触发 new.target === MyBase 分支)。
封装为可复用的基类工厂(可选进阶)
若需批量生成带兼容逻辑的基类,可抽象一个工厂函数:
function createCompatBase(initialize) {
return function Base(...args) {
if (!new.target) throw new TypeError('Base must be constructed');
// 仅顶层 new 调用才执行 initialize
if (new.target === Base) {
initialize.call(this, ...args);
}
};
}
// 使用
const Animal = createCompatBase(function(name) {
this.name = name;
this.id = Math.random();
});
后续所有继承自 Animal 的 class 或 Object.create 实例,都天然规避了重复初始化风险。










