首先我們先要了解new的原理
const Fn = function Fn(name) {
this.name = name
}
Fn.prototype = {
getName(){return this.name}
}
let f = new Fn('zs')
f => {name:'zs',__proto__ => Fn.prototype}
由此可以看出在new的過程中會(huì)將函數(shù)執(zhí)行埃撵,并且創(chuàng)建一個(gè)對(duì)象 且可以通過原型鏈調(diào)用構(gòu)造函數(shù)的原型方法,最后返回該實(shí)例
由此可以簡單實(shí)現(xiàn)出
const myNew = function myNew(Ctor,...params) {
let obj = {};
Ctor.call(obj,...params)
obj.__proto__ = Ctor.prototype;
return obj;
}
- 這個(gè)簡單的操作雖然實(shí)現(xiàn)了功能诱渤,但存在一些問題,比如【箭頭函數(shù)】是不能當(dāng)做構(gòu)造函數(shù)的谈况,原因是因?yàn)榧^函數(shù)沒有prototype這個(gè)屬性勺美,還有就是es6新增的一些數(shù)據(jù)類型也是不能通過new來構(gòu)造的,比如:Bigint碑韵,Symbol赡茸,還有g(shù)enerator函數(shù)
由此我們來對(duì)myNew進(jìn)行優(yōu)化
//首先先了解一下Object.create()
//Object.create(),接受一個(gè)構(gòu)造函數(shù),且該構(gòu)造函數(shù)必須要有原型對(duì)象祝闻,他會(huì)創(chuàng)造一個(gè)空對(duì)象然后使對(duì)象的原型鏈指向該構(gòu)造函數(shù)的原型
// {} {}.__proto__ => 構(gòu)造函數(shù)的原型對(duì)象
const myNew = function myNew(Ctor,...params) {
if(Ctor === BigInt || Ctor === Symbol || !Ctor.prototype || Object.prototype.toString.call(Ctor) !== '[object Function]'){
throw new TypeError('Ctor is not a constructor')
}
let obj = Object.create(Ctor.prototype);
let result = Ctor.call(obj,...params);
//如果該函數(shù)的返回值是對(duì)象或函數(shù),則會(huì)將該返回值賦值給子類
if(result !== null && /^(object|function)/.test(typeof result)) return result;
return obj
}
- Object.create() : 該函數(shù)接收一個(gè)構(gòu)造函數(shù)占卧,會(huì)返回一個(gè)對(duì)象,并使這個(gè)對(duì)象的proto屬性指向該構(gòu)造函數(shù)的原型联喘;