news 2026/10/29 8:53:45

jstips 第 52 期解读:深入理解 JavaScript `new` 运算符的返回值规则

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
jstips 第 52 期解读:深入理解 JavaScript `new` 运算符的返回值规则
  • 教程

【免费下载链接】jstips

This is about useful JS tips!

项目地址:https://gitcode.com/gh_mirrors/js/jstips
点击查看免费下载

在 JavaScript 中使用new调用构造函数时,函数的return语句到底还能不能起作用?本篇文章以 jstips 仓库 《new 的返回值》(英文原版见 Return Values with the 'new' Operator)为骨架,结合仓库内的相关技巧,完整梳理new的底层行为、原始值与非原始值返回值差异,以及不加new调用构造函数带来的全局污染陷阱,帮助你彻底掌握这一易混淆的 JavaScript 机制。

一、new的本质:构造一个新对象实例

new是 JavaScript 中用于分配新对象的运算符。在合理的情况下,它总会返回一个新对象的实例。看一个最基础的构造函数:

function Thing() { this.one = 1; this.two = 2; } var myThing = new Thing(); myThing.one // 1 myThing.two // 2

执行new Thing()时,引擎会做四件事:

  1. 创建一个全新的空对象;
  2. 将这个新对象绑定为函数体内的this;
  3. 执行构造函数体,通过this.xxx = ...为对象挂载属性;
  4. 根据函数的返回值决定最终返回什么(这正是本文要重点剖析的规则)。

在这个例子中,this指向的就是new产生的新对象,所以myThing拥有了one和two两个属性。

二、忘记new的代价:this指向全局对象与全局污染

文档中特别强调了一个易踩的坑:如果Thing()不是用new调用,那么不会创建新对象,此时函数内的this会指向全局对象——在浏览器环境中就是window。

Thing(); // 没有 new!

这会导致两个后果:

  1. 突然产生两个全局变量one和two——因为this.one = 1实际变成了window.one = 1,污染了全局命名空间;
  2. myThing为undefined——因为Thing()函数体内没有任何return语句,普通调用默认返回undefined。

这正是许多早期库代码里常见 bug 的根源:构造函数被误当成普通函数调用,属性全部泄漏到全局,而接收返回值的一方拿到的是undefined。ES6 引入的class语法在编译/运行层面进一步强化了这一约束——class构造函数如果不用new调用,会直接抛出TypeError,从语言层面杜绝了这种误用。

三、返回原始值:被静默忽略的return

接下来是本文最核心、最反直觉的部分。我们在构造函数里加一条return语句:

function Thing() { this.one = 1; this.two = 2; return 5; // 一个原始值 } var myThing = new Thing();

此时myThing到底等于多少?是5?是一个对象?还是两者皆非?

答案出人意料——myThing仍然是一个对象:

myThing.one // 1 myThing.two // 2

我们明明在构造函数里return 5,但这个5却"消失"了。这是因为:

使用new调用函数时,如果构造函数返回的是原始值(primitive,如数字、字符串、布尔值、null、undefined),该返回值会被直接忽略,new表达式最终返回的是this实例——即你通过this.one = 1;之类语句挂载了属性的那个对象。

也就是说,return 5这种写法在new语义下是无效的"死代码"。

四、返回非原始值:覆盖this实例

既然原始值会被忽略,那返回非原始值(引用类型)会怎样?文档紧接着给出了第三个示例——在构造函数中返回一个对象字面量:

function Thing() { this.one = 1; this.two = 2; return { three: 3, four: 4 }; } var myThing = new Thing();

用console.log直接打印全部内容:

console.log(myThing); /* Object {three: 3, four: 4} this.one 和 this.two 发生了什么!? 他们被覆盖了,朋友。 */

结果截然不同:myThing变成了{three: 3, four: 4},而你在构造函数里辛苦设置的this.one、this.two全都被丢弃了。

这是因为:当构造函数返回一个非原始值(对象object、数组array或函数function)时,这个非原始值会"踩掉"(stomp)this实例,成为new表达式的最终返回值——相当于你之前对this的所有赋值工作全部白做。

五、规则总结:一张表看清所有情况

把上面三个示例归纳成一条完整的判定规则:

构造函数中的return语句new表达式最终返回值说明
无return(或return;)this实例最常见的正常情况,如this.one = 1的赋值全部生效
return原始值(5、'str'、true、null等)this实例原始返回值被静默忽略,相当于没写
return非原始值(对象、数组、函数)返回的那个非原始值this实例被覆盖,之前的属性赋值失效
不用new直接调用取决于函数体return(通常为undefined)this指向全局对象,属性泄漏为全局变量

一句话记忆:返回原始值,拿回this;返回对象,对象说了算。

顺带一提,return原始值时对象本身并不会"消失"——this实例照样被创建并返回,只是那个原始值被丢弃;而返回对象时,this实例虽然在创建后被丢弃,但它在构造函数体内的赋值过程已经执行完毕(只是结果没人接收)。

六、仓库内相关技巧的印证与延伸

jstips 仓库中还有两篇与本文主题高度互补的技巧,可以加深理解:

  • 第 20 期:返回对象,使方法可以链式调用:该技巧在构造函数的方法中主动return this,从而实现person.sayName().changeName("Timmy").sayName()式的方法链。结合本文的规则看,return this返回的正是new创建的那个实例(非原始值),与"返回对象会覆盖默认返回"的规则完全自洽——这也是 jQuery 等库链式调用的底层模式。

  • 第 44 期:了解传值机制:该技巧讲解了对象作为参数时"引用值按值传递"的行为。理解这一点有助于区分:this实例本质上是引擎内部创建的对象引用,无论是被默认返回、被原始值忽略,还是被新对象覆盖,其背后都是引用语义在起作用。

从仓库结构看,每篇 tip 均遵循 POST_TEMPLATE.md 的规范组织(front matter 含layout、title、tip-number、tip-username等元信息),本文所述内容对应tip-number: 52,完整技巧列表可参见 README.md。

七、实战建议:如何安全地使用new

基于以上规则,给出几条可直接落地的编码建议:

  1. 构造函数不要返回原始值:return 5这类语句在new调用下是无效的,只会误导读者,应直接删除。
  2. 想覆盖默认实例时,显式返回对象:少数场景(如实现单例、返回工厂产物)可以利用"返回对象覆盖this"的特性,但务必在注释中说明,避免团队其他成员误读。
  3. 防止忘记new:在构造函数内部可以加防御性检查,例如if (!(this instanceof Thing)) return new Thing();,或在 ES6 中直接使用class,让引擎在未用new时抛错。
  4. 善用return this实现链式调用:参考上文第 20 期技巧,在方法内返回this实例,可获得流畅的链式 API。

八、小结

new运算符的返回值规则虽然反直觉,但底层逻辑非常清晰:

  • 有new+ 返回原始值→ 返回this实例;
  • 有new+ 返回非原始值→ 返回该非原始值,this实例被覆盖;
  • 无new→ 不创建新对象,this指向全局对象,属性泄漏、返回undefined。

理解了这三条规则,你就不会再被"构造函数里的return到底有没有用"这类问题困扰,也能更自信地设计构造函数、class 与链式 API。

  • 教程

【免费下载链接】jstips

This is about useful JS tips!

项目地址:https://gitcode.com/gh_mirrors/js/jstips
点击查看免费下载

相关推荐

上一篇:Semi Design Dropdown 下拉框组件完全指南:触发方式、嵌套菜单、JSON 配置与无障碍交互
下一篇:高效智能的Beat Saber插件管理:ModAssistant一站式解决方案

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 7:19:21

AI上下文模式实战:从Context Mode到项目级应用,决定AI生产力上限

上个月排查一个AI编码助手答非所问的问题时,我盯着配置面板里那个context-mode选项看了整整十分钟。明明是同一个模型,为什么有人用起来像资深架构师,有人用起来像刚毕业的实习生?后来我意识到,差距不在模型本身&#…

作者头像 李华
网站建设 2026/10/15 15:47:48

深入浅出运算放大器:分类、核心参数、典型电路与行业应用全解(一)

专栏定位:面向电子工程师、嵌入式开发者、硬件入门者,从基础分类到选型参数,从电路原理到行业落地,系统构建运放知识体系,看完即可独立完成运放选型与基础电路设计。 前言:为什么你必须系统掌握运放? 运算放大器(Operational Amplifier,简称 Op-Amp)是模拟电路的 “…

作者头像 李华