由此可以知道new 的优先级带参数的比不带的高
在第三种解析中我们要计算 new (foo.prototype.getName)() 的值,首先要明白new到底做了什么,其实就做了3件事
第一步:创建一个空对象
第二步:绑定该对象的原型
第三部:调用构造函数 // 执行了构造函数的内容
所以在 new (foo.prototype.getName)() 也就会返回foo.prototype.getName的一个实例,并且执行一次构造函数,也就是执行 console.log(3) ,打印3这个结果
手写new操作符的流程:
// 1.定义一个空对象
// 2.隐式原型指向构造函数的显式原型
// 3.执行构造函数,this指向空对象
// 4.返回对象
function myNew(fn,...args){
// 1.定义一个空对象
const obj={}
// 2.隐式原型指向构造函数的显式原型
obj._proto_=fn.prototype
// 3.执行构造函数,this指向空对象
fn.apply(obj,args)
// 4.返回对象
return obj
}
[toc]
new 操作符通过执行自定义构造函数或者js内置构造函数,从而生成一个实例对象。
mdn 上把内部操作大概分为4步:
通过一个简单的demo感受下上面的步骤
可以看到new操作符执行Person构造函数后,返回了一个内部创建的新对象, 并且以这个对象为上线文环境执行了一遍Person函数 ,最后将其返回,同时对象p的原型属性指向构造函数的原型, 这样也就保证了实例能够访问在构造函数原型中定义的属性和方法 。
上面的demo中构造函数是没有返回值的,如果说构造函数有返回值呢,如下
如果构造函数最后返回了一个对象,就会直接将其返回,而不是内部创建的新对象。
经过测试发现,除了返回对象,如果返回其他类型,只要最后返回的类型为引用类型 object 或者 function ( Function , Object , Array , Date , Error , Regexp ,要排除 null ,因为 typeof null === 'object' )就会直接将其返回,而其他基本类型都会返回内部新创建的对象。
这里我们尝试通过封装一个 myNew 方法模拟new操作符的主要功能:接受若干参数,第一个参数为构造函数 ctr ,其余为构造器所需参数, myNew(ctr, arg1, arg2,...)
这里的第一步把mdn中的1、2步放在了一起:创建一个新对象,并将其 __proto__ 属性指向构造函数的 prototype 属性
也可以使用如下方法
获取到参数之后,以内部新创建的对象 obj 为上线文执行构造函数,作用是为 obj 赋值
上面的 const args = [].slice.call(arguments, 1)用于将 arguments 类数组转为数组并获取参数,也可以通过 Array.form(arguments).slice(1) 或者 [...arguments].slice(1) 实现。
对执行构造函数后的返回值 result 做兼容处理。
如果构造函数最终返回对象、函数、数组、日期等其他引用类型及Symbol,会将其直接返回,其他基本类型及 null 、 undefined 会返回内部新创建的对象实例。
最后,简单测试一下
没有返回值
有返回值
面试官问:能否模拟实现JS的new操作符
手动实现一个new操作符理解