[toc]javascript
new
操做符经过执行自定义构造函数或者js内置构造函数,从而生成一个实例对象。java
mdn上把内部操做大概分为4步:面试
- 建立一个空的简单JavaScript对象(即{ } );
- 连接该对象(即设置该对象的构造函数)到另外一个对象 ;
- 将步骤1新建立的对象做为this的上下文 ;
- 若是该函数没有返回对象,则返回this。
经过一个简单的demo感觉下上面的步骤segmentfault
function Person (name){ this.name = name } let p = new Person('jack'); console.log(`p:`, p); // { name: 'jack' } console.log(`p.__proto__===Person.prototype:`,p.__proto__===Person.prototype); //true
能够看到new操做符执行Person构造函数后,返回了一个内部建立的新对象,而且以这个对象为上线文环境执行了一遍Person函数,最后将其返回,同时对象p的原型属性指向构造函数的原型,这样也就保证了实例可以访问在构造函数原型中定义的属性和方法。数组
上面的demo中构造函数是没有返回值的,若是说构造函数有返回值呢,以下app
function Person (name){ this.name = name; return {age: 18} } let p = new Person('jack'); console.log(`p:`, p); // { age: 18 }
若是构造函数最后返回了一个对象,就会直接将其返回,而不是内部建立的新对象。函数
通过测试发现,除了返回对象,若是返回其余类型,只要最后返回的类型为引用类型object
或者function
(Function
,Object
,Array
,Date
,Error
,Regexp
,要排除null
,由于typeof null === 'object'
)就会直接将其返回,而其余基本类型都会返回内部新建立的对象。post
这里咱们尝试经过封装一个myNew
方法模拟new操做符的主要功能:接受若干参数,第一个参数为构造函数ctr
,其他为构造器所需参数,myNew(ctr, arg1, arg2,...)
测试
这里的第一步把mdn中的一、2步放在了一块儿:建立一个新对象,并将其__proto__
属性指向构造函数的prototype
属性this
function myNew(ctr) { let obj = Object.create(ctr.prototype); }
也可使用以下方法
function myNew (ctr){ let obj = {}; obj.__proto__ = ctr.prototype; }
获取到参数以后,之内部新建立的对象obj
为上线文执行构造函数,做用是为obj
赋值
function myNew(ctr) { let obj = Object.create(ctr.prototype); const args = [].slice.call(arguments, 1); let result = ctr.apply(obj, args); console.log(`obj:`,obj); }
上面的const args = [].slice.call(arguments, 1);
用于将arguments
类数组转为数组并获取参数,也能够经过Array.form(arguments).slice(1)
或者[...arguments].slice(1)
实现。
对执行构造函数后的返回值result
作兼容处理。
若是构造函数最终返回对象、函数、数组、日期等其余引用类型及Symbol,会将其直接返回,其余基本类型及null
、undefined
会返回内部新建立的对象实例。
function myNew(ctr) { let obj = Object.create(ctr.prototype); const args = [].slice.call(arguments, 1); let result = ctr.apply(obj, args); var isObj = (typeof result === 'object' && result !== null); var isFn = typeof result === 'function'; return (isObj || isFn) ? result : obj; }
最后,简单测试一下
没有返回值
function Person(name) { this.name = name; } let p = myNew(Person,'jack'); console.log(`p:`,p);
有返回值
function Person(name) { this.name = name; return {age: 33} } let p = myNew(Person,'jack'); console.log(`p:`,p);