在 javascript 中防止构造函数被误用为普通函数调用,最稳妥的做法是在构造函数内部使用 new.target 进行判断。如果 new.target 为 undefined,说明代码是通过 person() 而非 new person() 调用的,此时直接抛出 error 异常即可阻止错误发生。

为什么直接调用构造函数会出错
当构造函数被当作普通函数调用时,this 的指向会发生改变。在非严格模式下,this 会指向全局对象(如浏览器中的 window),导致属性被意外挂载到全局环境;在严格模式下,this 为 undefined,尝试给 undefined 赋值会直接报错。无论哪种情况,都无法正确初始化实例对象。

function Person(name) {
if (this === undefined || typeof this !== 'object') {
throw new Error('Must use `new` to call Person');
}
this.name = name;
}
// 测试误用
try {
const p = Person('Alice'); // 抛出错误
} catch (e) {
console.log(e.message);
}使用 new.target 的现代写法
ES6 引入了 new.target 元属性,专门用于检测函数是否通过 new 运算符调用。这是目前推荐的标准做法,因为它语义清晰且能准确区分调用方式。
立即学习“Java免费学习笔记(深入)”;

function Person(name) {
if (!new.target) {
return new Person(name); // 兼容旧版:自动转为 new 调用
// 或者 throw new Error('...'); // 严格模式:直接报错
}
this.name = name;
}
const p1 = new Person('Bob');
console.log(p1 instanceof Person); // true
const p2 = Person('Charlie');
console.log(p2 instanceof Person); // true (因为上面用了兼容写法)基于 new.target 返回值的条件处理
在实际开发中,除了抛出错误,还可以利用 new.target 实现向后兼容。例如上面的代码所示,如果检测到非 new 调用,可以手动返回一个新的实例。这种做法既保留了传统函数的调用习惯,又确保了对象结构的正确性。需要注意的是,这种兼容写法要求构造函数内部逻辑完全独立于 this 的初始状态,否则可能引发副作用。


















