构造函数显式返回对象时,new 表达式结果被替换为该对象;返回原始值或无返回则仍返回新实例。此机制可用于单例、代理等劫持场景,但需注意原型链丢失、instanceof 失效等问题。

构造函数可以返回一个对象,此时 new 表达式的最终结果不再是默认创建的实例,而是构造函数显式返回的对象——这就是“劫持 new 结果”的核心机制。
构造函数返回值如何影响 new 的结果
JavaScript 中,new 调用构造函数时的行为分三步:创建空对象、绑定 this、执行函数体。但若构造函数有显式的 return 语句:
- 返回一个**对象(含数组、函数、正则、日期等引用类型)** →
new结果被替换为该对象; - 返回**原始值(string/number/boolean/null/undefined/symbol)** → 忽略返回值,仍返回新创建的实例;
- 不写
return或return;→ 默认返回新实例。
典型劫持场景:统一返回单例或代理对象
利用返回值覆盖,可实现单例封装、对象代理、类型校验等逻辑:
function Logger(name) {
this.name = name;
this.level = 'INFO';
// 拦截:始终返回预设的共享实例
if (!Logger.instance) {
Logger.instance = this;
}
return Logger.instance; // 劫持成功:所有 new Logger() 都返回同一个对象
}
再比如返回一个带拦截能力的代理:
function SafeObject(data) {
this.data = data;
// 返回一个 Proxy,隐藏原始 this
return new Proxy(this, {
get(target, key) {
if (key in target) return target[key];
return 'missing';
}
});
}
注意事项与陷阱
这种劫持方式看似灵活,但需注意:
-
无法继承原型链:若返回的是字面量对象(如
{}),它不会自动拥有构造函数的prototype,instanceof会失效; -
避免意外覆盖:返回非对象值(如
return 42)等于没劫持,容易误判; -
箭头函数不能作为构造函数,自然也无法用于
new劫持; - ES6 类的
constructor中return同样生效,但必须返回对象,否则报错(类构造器强制要求返回对象或 undefined)。
替代方案对比:Reflect.construct 与工厂函数
现代开发中,更推荐用明确的工厂函数代替隐式劫持:
const createLogger = (name) => {
const instance = { name, level: 'INFO' };
return new Proxy(instance, { /* ... */ });
};
这样语义清晰、可测试性强,且不依赖 new 的副作用行为。只有在需要兼容旧代码或封装底层 API 时,才谨慎使用构造函数返回值劫持。










