? ? ? 我們已經(jīng)了解了原型中繼承的概念,現(xiàn)在說(shuō)一下常用的call()和apply()。
? ? ? 每個(gè)函數(shù)都涵蓋了兩個(gè)非繼承而來(lái)的方法:call和apply。它們的作用是相同的,都是在某一個(gè)函數(shù)當(dāng)前執(zhí)行上下文中調(diào)用函數(shù)。等于設(shè)置函數(shù)體內(nèi)this對(duì)象的值,以擴(kuò)充函數(shù)運(yùn)行的作用域。簡(jiǎn)單來(lái)說(shuō),this總是指向某個(gè)方法的對(duì)象,而使用call()和apply()方法時(shí)候,就會(huì)改變this的指向,所以,我們可以把call和apply看做是某個(gè)對(duì)象的方法,通過(guò)調(diào)用的方法的形式,簡(jiǎn)接調(diào)用函數(shù)。
? ? ? call()方法使用舉例:
? ? function ShaoLin(quanfa,gunfa,tuifa){
? ? ? ? ? this.quanfa = quanfa;
? ? ? ? ? this.gunfa = gunfa;
? ? ? ? ? this.tuifa = tuifa;
}
? ? ? function WuDang(jianfa,daofa){
? ? ? ? ? ? this.jianfa = jianfa;
? ? ? ? ? ? this.daofa = daofa;
}
? ? ? function EMei(neigong){
? ? ? ? ? ? ? this.neigong = neigong;
}
? ? function ZhangSanFeng(){
};
var zhangsanfeng = new ZhangSanFeng();
上述代碼我們簡(jiǎn)單梳理一下,前三個(gè)構(gòu)造函數(shù)分別都是有形參的,在這里用了武林門派當(dāng)作函數(shù)名,形參用武功來(lái)表示,最后一個(gè)構(gòu)造函數(shù)相當(dāng)于一個(gè)人,這個(gè)人要去訪遍武學(xué)門派并習(xí)得鎮(zhèn)派武功,然后匯集于一身。我們可以通過(guò)call,在ZhangSanFeng這個(gè)構(gòu)造函數(shù)里間接的調(diào)用上面其他函數(shù)的對(duì)象屬性。寫法如下。
function ZhangSanFeng(quanfa,gunfa,tuifa,jianfa,daofa,neigong){
? ? ? ShaoLin.call(this,quanfa,gunfa,tuifa);
? ? ? WuDang.call(this,jianfa,daofa);
? ? ? EMei.call(this,neigong);
}
注意看首先在這個(gè)構(gòu)造函數(shù)里,寫了形參,都是之前的構(gòu)造函數(shù)里的參數(shù),全部寫進(jìn)去了。然后第二點(diǎn),call的用法,用黑體標(biāo)記了。函數(shù)名后面緊跟call()。且都有this,后面才跟著這個(gè)函數(shù)的形參。這個(gè)this代表著當(dāng)前調(diào)用的函數(shù)母對(duì)象。寫到這一步,可以傳實(shí)參進(jìn)去測(cè)試:
var zhangsanfeng = new ZhangSanFeng(“羅漢拳”,“達(dá)摩棍”,“金剛腿”,“太極劍”,“八卦刀”,“九陽(yáng)神功”)
這時(shí)候到控制臺(tái)可以輸入zhangsanfeng看看現(xiàn)在這些參數(shù)都會(huì)傳進(jìn)來(lái)了。仔細(xì)看看,ZhangSanFeng這個(gè)函數(shù)可是一行屬性都沒寫,全部都是用的別的函數(shù)的成果。就好比,他本身一點(diǎn)武功沒有,去這個(gè)門派拿了內(nèi)功心法,去那個(gè)門派拿了刀劍心得。這種做法在工作中也會(huì)用到。如果你寫的東西,剛好有別人寫過(guò)了,你寫的又全涵蓋他寫的,可以直接調(diào)用。好比別人寫的是零部件,你拿過(guò)來(lái)組裝。合成一個(gè)整體。
? ? ? 說(shuō)完了call(),再說(shuō)說(shuō)apply(),他們倆作用是一樣的,其實(shí)用法都差不多,不同點(diǎn)是apply()里面只能傳一個(gè)數(shù)組形式的參數(shù)。
? ? ? call需要把實(shí)參按照形參個(gè)數(shù)傳進(jìn)去
? ? ? apply需要傳一個(gè)arguments
結(jié)合上述例子,用法也很直觀:
? ? 函數(shù)名.call(this,形參1,形參2,形參3)
? 函數(shù)名.apply(this,【形參1,形參2,形參3】)
? ? ? 再補(bǔ)一個(gè)知識(shí)點(diǎn),前面提到過(guò)prototype(顯示原型),一個(gè)函數(shù)被創(chuàng)建之后都會(huì)擁有一個(gè)名為prototype的屬性,這個(gè)屬性指向當(dāng)前函數(shù)作為構(gòu)造函數(shù)構(gòu)造出來(lái)的對(duì)象的原型對(duì)象。劃重點(diǎn):__ptoto__是每個(gè)對(duì)象都有的一個(gè)屬性,且為隱式原型。
這兩個(gè)屬性的是有區(qū)別的:
__proto__是每個(gè)對(duì)象都有的屬性(包括構(gòu)造函數(shù)),而prototype是函數(shù)才會(huì)有的屬性。
__proto__是指向當(dāng)前對(duì)象的原型對(duì)象,而prototype是指向它的構(gòu)造函數(shù)的原型對(duì)象。
兩個(gè)屬性的作用:
都是為了繼承;
prototype是用來(lái)實(shí)現(xiàn)基于原型的繼承和屬性的共享;
__proto__(這種下劃線寫法是規(guī)定的)構(gòu)成了原型鏈,同樣用于實(shí)現(xiàn)基于原型的繼承,舉個(gè)例子,當(dāng)我們?cè)L問(wèn)一個(gè)對(duì)象的某屬性時(shí)候,如果在該對(duì)象中找不到,就會(huì)沿著__proto__依次查找;

可以看到圖片左上方兩個(gè)對(duì)象f1和f2的屬性__proto__指向了構(gòu)造函數(shù)Foo()的prototype原型對(duì)象。
構(gòu)造函數(shù)Foo()原型屬性prototype指向了它的構(gòu)造函數(shù)原型對(duì)象。
Object.prototype的__proto__屬性指向null。