簡(jiǎn)單實(shí)現(xiàn)
其實(shí)new操作符實(shí)現(xiàn)還是很簡(jiǎn)單的淮菠,因?yàn)镸dn上總共也就是4句話(huà)來(lái)描述它的作用
- 創(chuàng)建一個(gè)空的簡(jiǎn)單JavaScript對(duì)象(即
{}
); - 為步驟1新創(chuàng)建的對(duì)象添加屬性 proto 丽惭,將該屬性鏈接至構(gòu)造函數(shù)的原型對(duì)象 ;
- 將步驟1新創(chuàng)建的對(duì)象作為
this
的上下文 ; - 如果該函數(shù)沒(méi)有返回對(duì)象信殊,則返回
this
。
我們首先來(lái)依次用代碼來(lái)翻譯上面的四句話(huà)
function newOperator() {
// 創(chuàng)建對(duì)象
const obj = {}
// 創(chuàng)建的對(duì)象添加屬性__proto__,并指向構(gòu)造函數(shù)的原型對(duì)象
obj.__proto__ = Constructor.prototype
// 創(chuàng)建的對(duì)象作為this的上下文,并獲取返回值
const ret = Constructor.apply(obj, arguments)
// 如果該函數(shù)沒(méi)有返回對(duì)象汁果,則返回新創(chuàng)建的對(duì)象
return typeof ret === "object" ? ret : obj;
}
上面的代碼已經(jīng)很好的翻譯了上面的四句話(huà)涡拘,但是我們卻不能直接用來(lái)創(chuàng)建構(gòu)造函數(shù)的實(shí)例,因?yàn)槲覀兏緵](méi)有把構(gòu)造函數(shù)傳進(jìn)去据德,即上面的代碼是無(wú)法運(yùn)行的鳄乏,因?yàn)?strong>Constructor并沒(méi)有定義
代碼完善
那么就讓我們來(lái)重新完善一下上面的代碼, 步驟如下:
- 首先新增參數(shù)棘利,即需要實(shí)例的構(gòu)造函數(shù)
function newOperator(ctor) {}
- 判斷ctor參數(shù)類(lèi)型橱野,是否是function類(lèi)型,否則拋出錯(cuò)誤
if (typeof ctor !== "function") {
throw '參數(shù)異常赡译,只接收構(gòu)造函數(shù)'
}
- 新建實(shí)例和為對(duì)象添加__proto仲吏,并指向構(gòu)造函數(shù)的原型對(duì)象
// 創(chuàng)建對(duì)象
const obj = {}
// 創(chuàng)建的對(duì)象添加屬性__proto__,并指向構(gòu)造函數(shù)的原型對(duì)象
obj.__proto__ = Constructor.prototype
// 上面的代碼等同于如下代碼
const obj = Object.create(ctor.prototype)
- 處理參數(shù)
const params = [].slice.call(arguments, 1)
const result = ctor.apply(obj, params)
此處解釋一下為什么要處理一下參數(shù)
function Dog (name, age) {
this.name = name
this.age = age
}
const maomao = newOperator(Dog, 'maomao', 2)
從上面的代碼可以看出來(lái),我們使用newOperator
的時(shí)候,第一個(gè)參數(shù)是構(gòu)造函數(shù)裹唆,所以需要把第一個(gè)參數(shù)截取掉誓斥,獲取到的參數(shù)就是['maomao', 2],這兩個(gè)才是構(gòu)造函數(shù)的參數(shù)
-
改變
this
上下文并獲取構(gòu)造的返回結(jié)果
const result = ctor.apply(obj, params)
為什么要獲取構(gòu)造的返回結(jié)果许帐?劳坑?
因?yàn)橥ǔ?lái)說(shuō)實(shí)現(xiàn)構(gòu)造函數(shù)是不需要return來(lái)返回結(jié)果的,但是如果真的給構(gòu)造函數(shù)添加return
關(guān)鍵字并返回結(jié)果成畦,我們也應(yīng)該返回這個(gè)結(jié)果,像如下代碼
function Cat(name, age) {
return {
name: name,
age: age
}
}
- 判斷類(lèi)型并返回
const isObject = typeof result === 'object'
const isFunction = typeof result === 'function'
if (isFunction || isObject) {
return result
}
return obj
完整代碼
function newOperator(ctor) {
if (typeof ctor !== "function") {
throw '參數(shù)異常距芬,只接收構(gòu)造函數(shù)'
}
const obj = Object.create(ctor.prototype)
const params = [].slice.call(arguments, 1)
const result = ctor.apply(obj, params)
const isObject = typeof result === 'object'
const isFunction = typeof result === 'function'
if (isFunction || isObject) {
return result
}
return obj
}