前几天无意间发现了刚开始学JavaScript时在知乎写的一些回答,有一个就是讲new操作符到底干了什么。从现在的视角看我当时的回答虽然是正确的,但是在对原理的剖析和细节的理解上还相去甚远。所以借此机会,就想重新梳理一下这一年多来对new操作符理解的变化与成长。

模拟new操作符

第一次去了解new操作符,是在看《JS高级程序设计(第三版)》这本书时,P145是这样写到的。

要创建Person的新实例,必须使用new操作符。以这种方式调用构造函数实际上会经历以下4个步骤:

  1. 创建一个新对象;
  2. 将构造函数的作用域赋给新对象(因此this就指向了这个新对象);
  3. 执行构造函数中的代码(为这个新对象添加属性);
  4. 返回新对象;

尽管书中是这样描述,但是并没有给出实践的代码,所以我就按照这个步骤自己去实践模拟一个new操作符。代码如下:

var mockNew = function (constructor) {var o = {} // 创建一个新对象constructor.apply(o, Array.prototype.slice.call(arguments, 1)) // 赋作用域 执行代码return o // 返回新对象
}
复制代码

然后我们用这个模拟new操作符的函数来创造一个对象试试。

var Person = function (name, age) {this.name = namethis.age = age
}Person.prototype.sayName = function () {console.log(this.name)
}var person1 = mockNew(Person, 'MeloGuo', 22)console.log(person1.name) // 'MeloGuo'
console.log(person1.age) // 22
person1.sayName() // Uncaught TypeError: person1.sayName is not a function
复制代码

看起来我的模拟函数虽然能访问实例中的属性,但是却不能访问sayName方法,而且当我使用instanceof操作符检测时却得到了这样的结果。

console.log(person1 instanceof Person) // false
console.log(person1 instanceof Object) // true
复制代码

改进的模拟函数

可见person1并不是Person的实例。当时的我还不知道问题出在哪里,直到学习到原型链时我才直到mockNew函数缺少了一个步骤,即绑定构造函数原型。所以person1实例是无法访问到Person原型中的sayName方法,同时instanceof操作符的结果也为false。因为instanceof操作符是用来检测一个对象在其原型链中是否存在一个构造函数的prototype属性的,而person1的原型链中并不存在Person.prototype,所以返回值为false。因此,我们改造mockNew函数如下:

var mockNew = function (constructor) {var o = {}o.__proto__ = constructor.prototype // 绑定构造函数原型,但是生产代码中千万别用.__proto__constructor.apply(o, Array.prototype.slice.call(arguments, 1))return o
}
复制代码

这时我们再创建实例,然后使用instanceof操作符检测一下,同时调用下sayName方法。

var person1 = mockNew(Person, 'MeloGuo', 22)console.log(person1 instanceof Person) // true
console.log(person1 instanceof Object) // true
person1.sayName() // 'MeloGuo'
复制代码

这时看似mockNew函数已经完全模拟了new操作符了,但是当我们尝试下面这种情况时,又出现了问题。

function Person (name) {this.name = namereturn { age: 22 }
}var person1 = new Person('MeloGuo')
var person2 = mockNew(Person, 'MeloGuo')console.log(person1) // {age: 22}
console.log(person2) // Person {name: "MeloGuo"}
console.log(person1 instanceof Person) // false
console.log(person2 instanceof Person) // true
复制代码

什么!!!用new操作符调用的Person构造函数并没有按照预期返回带有name属性并且在Person.prototype上的对象,而是返回了我们手动return的带有age属性的对象,但是我们的mockNew函数是正常返回了。所以我们的mockNew函数中肯定又丢失了一些细节,为了弄清楚,只好硬着头皮去读ECMA-262规范了。看到规范中的steps后才恍然大悟了new操作符的整个执行流程。

完善模拟函数

简单来说我们在返回对象前缺失了判断返回值类型的步骤。

  • 如果构造函数的返回值是值类型,那么就丢弃掉,依然返回构造函数创建的实例。
  • 如果构造函数的返回值是引用类型,那么就返回这个引用类型,丢弃构造函数创建的实例。

注:如果没有显示return,那么相当于隐式返回了undefined,则丢弃它。

吸取了规范中的内容,并且加入ES6语法后,我们新的mockNew函数如下:

function mockNew (constructor, ...args) {const isPrimitive = result => {// 如果result为值类型则返回true// 如果result为引用类型则返回false    }const o = Object.create(constructor.prototype)const result = constructor.apply(o, args)return isPrimitive(result) ? o : result
}
复制代码

这时的mockNew函数可以说是较好的模拟了new操作符的功能。

总结

其实new操作符就是一个语法糖。在传统的面向类的语言中,“构造函数”是类中的一些特殊方法,使用new初始化类时会调用类中的构造函数。而JavaScript中的new其实是用来告诉函数,我要以“构造”的方式调用你了,从而向mockNew函数中的流程一样,得到我们的实例。所以本质上来说JS是没有所谓构造函数的,有的应该是构造调用。这样的称呼能让我们更清楚认识JS中的new操作符。

转载于:https://juejin.im/post/5b4af862e51d4519984118d1

new操作符到底干了什么?相关推荐

  1. web面试 new操作符到底干了什么?

    面试或者笔试经常会遇到的 如果就回答创建了一个对象 ok 那gg了 面试官看来就是菜鸟一枚 所以知道什么就说什么 蒙在心里谁知道你的水有多深呢? 呢?呢? new操作符应该是进行了四个操作 1,创建一 ...

  2. new 操作符具体干了什么

    一.定义 new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象类型之一 在创建一个新的实例的时候,必须使用 new 操作符.而使用 new 操作符会经历以下 4 个步骤: 创建一个新 ...

  3. new操作符具体干了啥

    new操作符具体干了啥 我们平常见到就是 这样new的一个实例 function Base(name) {this.name = name;}Base.prototype.showName = fun ...

  4. 项目管理课件_项目管理(PMO)工作到底干些啥?

    可能大家都会疑惑,项目管理工作到底干些啥?如何来做价值提升?最近刚好沉淀下来整理一下项目管理的工作,当然还不全面,后续会持续补充. 从我个人经验来理解项目管理,他的工作职责主要是以下几大块(每个公司对 ...

  5. python程序的name的作用是什么_python 中__name__ = '__main__' 的作用,到底干嘛的?

    python 中__name__ = 'main' 的作用,到底干嘛的? 有句话经典的概括了这段代码的意义: "Make a script both importable and execu ...

  6. 我这半年到底干了啥(附多家详细面经)

    有现实中的小伙伴问我,我这半年到底干了啥.怎么博客突然不更新了? 最近的一次更新还是在去年12月 其实这半年嘛,一直在为面试做准备.算法一直是我的弱项,于是突击了力扣. 开了会员,刷了将近700道,有 ...

  7. Pytorch(GPU)配环境原理:cuda+cudnn+pytorch配环境的每一步到底干了些什么?

    作者:18届cyl 时间:2022.5.11 参考文章:https://blog.csdn.net/qq_42406643/article/details/109545766 最近帮舍友配pytorc ...

  8. Tomcat 到底干了啥

    道阻且长,行则将至.请相信我,你一定会更优秀! 此文为Tomcat系列的第一篇,Tomcat的整体架构个人感觉非常有意思,本文我们先非常简单的入个门. 先抛开对 Tomcat 的认识,想一下,如果没有 ...

  9. pygame.error: font not initialized的解决及init()到底干了什么

    环境 Python3.6.8 pygame1.9.4 贴上报错源码: import pygame my_font = pygame.font.SysFont('arial', 16) my_font ...

最新文章

  1. 万字总结,体系化带你全面认识 Nginx
  2. 变量作用域与预处理命令习题
  3. free5GC — 部署端到端 5G 实验网络
  4. Linux内核编译学习1
  5. 关于php的文章,一篇关于 PHP 性能的文章
  6. python 温度插值nan处理_Python处理inf和Nan值,pytorch,nan,数值
  7. sqlsession.selectlist 会返回null么_StackOverflow经典问题:代码中如何去掉烦人的“!=nullquot;判空语句...
  8. 安装Ubunutu音频视频库
  9. 让你的php命令行程序处理管道数据
  10. 人脸识别中Softmax-based Loss的演化史
  11. 一文掌握GaussDB(DWS) SQL进阶技能:全文检索
  12. Web应用运行在pywebview在窗口
  13. php mui.picker,www MUI框架里边有很多例子教你如何使用 开发手机界面 WEB(ASP,PHP,...) 251万源代码下载- www.pudn.com...
  14. iPhone13 系列售价曝光:没有涨价;曝华为P50系列7月29日发布;丁磊称专业比学校更重要:你同意吗?|极客头条...
  15. php properties,PHP ReflectionClass getStaticProperties()用法及代码示例
  16. python写sql语句_Python 数据分析:让你像写 Sql 语句一样,使用 Pandas 做数据分析...
  17. win10新版蓝牙驱动没有电源管理问题
  18. java在线ide_程序猿专用十大在线编译器(IDE)整理
  19. 算法思想(枚举)——百钱百鸡+生理周期+完美立方+熄灯问题+讨厌的青蛙
  20. Android 10.0 Activity启动详解(二)

热门文章

  1. Shopee上线全球类目树,类目垂直定位,让商家引流更精准!
  2. 功能性农业投融资-农业大健康·周荣江:国情讲坛体制创新
  3. spoj Longest Common Substring II
  4. mysql数据库优化的几种方法
  5. HTML5 音频audio 和视频video实用基础教程
  6. 两种CSS3圆环进度条详解
  7. 传雅虎有意收购Hulu 竞争者达6家
  8. 用于弹出ModalDialog进行数据选择的控件
  9. B端产品思维全解析,提升产品经理核心竞争力
  10. 平台电商类的增长策略:从用户激励到养成类游戏