這篇文章主要講解了“如何理解JS中的面向?qū)ο蟆?,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“如何理解JS中的面向?qū)ο蟆卑桑?/p>
創(chuàng)新互聯(lián)公司于2013年成立,先為崇州等服務(wù)建站,崇州等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為崇州企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。
在講這個(gè)之前我們先來(lái)說(shuō)說(shuō)類(lèi),了解面向?qū)ο蟮呐笥褢?yīng)該都知道,如果我要定義一個(gè)通用的類(lèi)型我可以使用類(lèi)(class)。比如在java中我們可以這樣定義一個(gè)類(lèi):
public class Puppy{ int puppyAge; public Puppy(age){ puppyAge = age; } public void say() { System.out.println("汪汪汪"); } }
上述代碼我們定義了一個(gè)Puppy類(lèi),這個(gè)類(lèi)有一個(gè)屬性是puppyAge,也就是小狗的年齡,然后有一個(gè)構(gòu)造函數(shù)Puppy(),這個(gè)構(gòu)造函數(shù)接收一個(gè)參數(shù),可以設(shè)置小狗的年齡,另外還有一個(gè)說(shuō)話的函數(shù)say。這是一個(gè)通用的類(lèi),當(dāng)我們需要一個(gè)兩歲的小狗實(shí)例是直接這樣寫(xiě),這個(gè)實(shí)例同時(shí)具有父類(lèi)的方法:
Puppy myPuppy = new Puppy( 2 ); myPuppy.say(); // 汪汪汪
但是早期的JS沒(méi)有class關(guān)鍵字啊(以下說(shuō)JS沒(méi)有class關(guān)鍵字都是指ES6之前的JS,主要幫助大家理解概念,本文不涉及ES6的class),JS為了支持面向?qū)ο?,使用了一種比較曲折的方式,這也是導(dǎo)致大家迷惑的地方,其實(shí)我們將這種方式跟一般的面向?qū)ο箢?lèi)比起來(lái)就很清晰了。下面我們來(lái)看看JS為了支持面向?qū)ο笮枰鉀Q哪些問(wèn)題,都用了什么曲折的方式來(lái)解決。
沒(méi)有class,用函數(shù)代替
首先JS連class關(guān)鍵字都沒(méi)有,怎么辦呢?用函數(shù)代替,JS中最不缺的就是函數(shù),函數(shù)不僅能夠執(zhí)行普通功能,還能當(dāng)class使用。比如我們要用JS建一個(gè)小狗的類(lèi)怎么寫(xiě)呢?直接寫(xiě)一個(gè)函數(shù)就行:
function Puppy() {}
這個(gè)函數(shù)可以直接用new關(guān)鍵字生成實(shí)例:
const myPuppy = new Puppy();
這樣我們也有了一個(gè)小狗實(shí)例,但是我們沒(méi)有構(gòu)造函數(shù),不能設(shè)置小狗年齡啊。
函數(shù)本身就是構(gòu)造函數(shù)
當(dāng)做類(lèi)用的函數(shù)本身也是一個(gè)函數(shù),而且他就是默認(rèn)的構(gòu)造函數(shù)。我們想讓Puppy函數(shù)能夠設(shè)置實(shí)例的年齡,只要讓他接收參數(shù)就行了。
function Puppy(age) { this.puppyAge = age; } // 實(shí)例化時(shí)可以傳年齡參數(shù)了 const myPuppy = new Puppy(2);
注意上面代碼的this,被作為類(lèi)使用的函數(shù)里面this總是指向?qū)嵗瘜?duì)象,也就是myPuppy。這么設(shè)計(jì)的目的就是讓使用者可以通過(guò)構(gòu)造函數(shù)給實(shí)例對(duì)象設(shè)置屬性,這時(shí)候console出來(lái)看
myPuppy.puppyAge就是2。console.log(myPuppy.puppyAge); // 輸出是 2
實(shí)例方法用prototype
上面我們實(shí)現(xiàn)了類(lèi)和構(gòu)造函數(shù),但是類(lèi)方法呢?Java版小狗還可以“汪汪汪”叫呢,JS版怎么辦呢?JS給出的解決方案是給方法添加一個(gè)prototype屬性,掛載在這上面的方法,在實(shí)例化的時(shí)候會(huì)給到實(shí)例對(duì)象。我們想要myPuppy能說(shuō)話,就需要往Puppy.prototype添加說(shuō)話的方法。
Puppy.prototype.say = function() { console.log("汪汪汪"); }
使用new關(guān)鍵字產(chǎn)生的實(shí)例都有類(lèi)的prototype上的屬性和方法,我們?cè)赑uppy.prototype上添加了say方法,myPuppy就可以說(shuō)話了,我么來(lái)試一下:
myPuppy.say(); // 汪汪汪
實(shí)例方法查找用__proto__
那myPuppy怎么就能夠調(diào)用say方法了呢,我們把他打印出來(lái)看下,這個(gè)對(duì)象上并沒(méi)有say啊,這是從哪里來(lái)的呢?
自己實(shí)現(xiàn)一個(gè)instanceof
知道了原理,其實(shí)我們也知道了instanceof是干啥的。instanceof不就是檢查一個(gè)對(duì)象是不是某個(gè)類(lèi)的實(shí)例嗎?換句話說(shuō)就是檢查一個(gè)對(duì)象的的原型鏈上有沒(méi)有這個(gè)類(lèi)的prototype,知道了這個(gè)我們就可以自己實(shí)現(xiàn)一個(gè)了:
function myInstanceof(targetObj, targetClass) { // 參數(shù)檢查 if(!targetObj || !targetClass || !targetObj.__proto__ || !targetClass.prototype){ return false; } let current = targetObj; while(current) { // 一直往原型鏈上面找 if(current.__proto__ === targetClass.prototype) { return true; // 找到了返回true } currentcurrent = current.__proto__; } return false; // 沒(méi)找到返回false } // 用我們前面的繼承實(shí)驗(yàn)下 function Parent() {} function Child() {} Child.prototype.__proto__ = Parent.prototype; const obj = new Child(); console.log(myInstanceof(obj, Child) ); // true console.log(myInstanceof(obj, Parent) ); // true console.log(myInstanceof({}, Parent) ); // false
感謝各位的閱讀,以上就是“如何理解JS中的面向?qū)ο蟆钡膬?nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)如何理解JS中的面向?qū)ο筮@一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!