ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

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

jstips 第 52 期解读:深入理解 JavaScript `new` 运算符的返回值规则 教程【免费下载链接】jstipsThis 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()时引擎会做四件事创建一个全新的空对象将这个新对象绑定为函数体内的this执行构造函数体通过this.xxx ...为对象挂载属性根据函数的返回值决定最终返回什么这正是本文要重点剖析的规则。在这个例子中this指向的就是new产生的新对象所以myThing拥有了one和two两个属性。二、忘记new的代价this指向全局对象与全局污染文档中特别强调了一个易踩的坑如果Thing()不是用new调用那么不会创建新对象此时函数内的this会指向全局对象——在浏览器环境中就是window。Thing(); // 没有 new这会导致两个后果突然产生两个全局变量one和two——因为this.one 1实际变成了window.one 1污染了全局命名空间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时这个非原始值会踩掉stompthis实例成为new表达式的最终返回值——相当于你之前对this的所有赋值工作全部白做。五、规则总结一张表看清所有情况把上面三个示例归纳成一条完整的判定规则构造函数中的return语句new表达式最终返回值说明无return或return;this实例最常见的正常情况如this.one 1的赋值全部生效return原始值5、str、true、null等this实例原始返回值被静默忽略相当于没写return非原始值对象、数组、函数返回的那个非原始值this实例被覆盖之前的属性赋值失效不用new直接调用取决于函数体return通常为undefinedthis指向全局对象属性泄漏为全局变量一句话记忆返回原始值拿回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基于以上规则给出几条可直接落地的编码建议构造函数不要返回原始值return 5这类语句在new调用下是无效的只会误导读者应直接删除。想覆盖默认实例时显式返回对象少数场景如实现单例、返回工厂产物可以利用返回对象覆盖this的特性但务必在注释中说明避免团队其他成员误读。防止忘记new在构造函数内部可以加防御性检查例如if (!(this instanceof Thing)) return new Thing();或在 ES6 中直接使用class让引擎在未用new时抛错。善用return this实现链式调用参考上文第 20 期技巧在方法内返回this实例可获得流畅的链式 API。八、小结new运算符的返回值规则虽然反直觉但底层逻辑非常清晰有new 返回原始值→ 返回this实例有new 返回非原始值→ 返回该非原始值this实例被覆盖无new→ 不创建新对象this指向全局对象属性泄漏、返回undefined。理解了这三条规则你就不会再被构造函数里的return到底有没有用这类问题困扰也能更自信地设计构造函数、class 与链式 API。赞分享教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载相关推荐深入理解 JavaScript 逻辑或 ||从 alert( null || 2 || undefined ) 看返回第一个真值的求值规则深入理解 JavaScript 逻辑或 || 从 alert null || 2 || undefined 看返回第一个真值的求值规则 本篇指南围绕 Mo文档/教程前端如何正确理解bash正则匹配~运算符的返回值解析如何正确理解bash正则匹配~运算符的返回值解析 bash正则表达式匹配是Shell脚本编程中的核心技能之一其中 ~ 运算符是实现模式匹配的关键工具。本教程3大技术突破ElasticFusion如何实现实时密集视觉SLAM的革命性创新3大技术突破ElasticFusion如何实现实时密集视觉SLAM的革命性创新 在机器人导航、增强现实和三维重建领域实时密集视觉SLAM技术一直是研究的热点计算机视觉上一篇Semi Design Dropdown 下拉框组件完全指南触发方式、嵌套菜单、JSON 配置与无障碍交互下一篇高效智能的Beat Saber插件管理ModAssistant一站式解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表