關(guān)于JS原型的解釋,查看網(wǎng)上的資料, 大多數(shù)都看的云里霧里, 其主要原因就是, 在解釋前很多都忽略了普通用戶對(duì)一些專業(yè)名詞、概念本身就不懂的情況,本身就暈, 里面的解釋, 也是暈的, 看似都是漢字, 數(shù)數(shù)都認(rèn)識(shí), 但看結(jié)果, 還是暈糊糊,導(dǎo)致大家走了很多很多彎路
一、首先在我們對(duì)JS原型進(jìn)行解釋的時(shí)候,我們首先要理解涉到的兩個(gè)概念:構(gòu)造函數(shù)、原型對(duì)象
構(gòu)造函數(shù):在script標(biāo)簽里面聲明的那個(gè)函數(shù)(注意: 區(qū)分與JAVA,PHP,Python等后臺(tái)語(yǔ)言不要混為一談)
如下
<script> function person(name,age){ this.name = name; this.age = age; //在這里, 整個(gè)函數(shù)就是構(gòu)造函數(shù) } </script>
2. 原型對(duì)象:在聲明上面這個(gè)函數(shù)后,瀏覽器會(huì)自動(dòng)按照一定的規(guī)則在內(nèi)存中創(chuàng)建一個(gè)對(duì)象,這個(gè)對(duì)象就叫做原型對(duì)象
3.在聲明了一個(gè)函數(shù)后,這個(gè)構(gòu)造函數(shù)(即聲明了的函數(shù))中會(huì)有一個(gè)屬性prototype,這個(gè)屬性指向的就是這個(gè)構(gòu)造函數(shù)對(duì)應(yīng)的原型對(duì)象;原型對(duì)象中有一個(gè)屬性constructor,這個(gè)屬性指向的是這個(gè)構(gòu)造函數(shù)下面一張圖可以很簡(jiǎn)單理解:看圖會(huì)意
二、使用構(gòu)造函數(shù)創(chuàng)建對(duì)象
此時(shí),p1就是那個(gè)構(gòu)造函數(shù)person創(chuàng)建出來(lái)的對(duì)象,這個(gè)對(duì)象中是沒(méi)有prototype屬性的,prototype屬性只有在構(gòu)造函數(shù)person中有,請(qǐng)看圖!
var p1 = new person("莊子",18); console.dir(p1); console.log("----------------------------------------"); console.dir(person)
可以看出,構(gòu)造函數(shù)person中有prototype屬性,指向的是person對(duì)應(yīng)的原型對(duì)象;
而p1是構(gòu)造函數(shù)person創(chuàng)建出來(lái)的對(duì)象,它不存在prototype屬性,但p1有一個(gè)__proto__屬性,stu調(diào)用這個(gè)屬性可以直接訪問(wèn)到構(gòu)造函數(shù)person的原型對(duì)象(也就是說(shuō),p1的__proto__屬性指向的是構(gòu)造函數(shù)的原型對(duì)象),請(qǐng)看圖
從上面的代碼中可以看到,創(chuàng)建p1對(duì)象雖然使用的是person構(gòu)造函數(shù),但是對(duì)象創(chuàng)建出來(lái)之后,這個(gè)p1對(duì)象其實(shí)已經(jīng)與person構(gòu)造函數(shù)沒(méi)有任何關(guān)系了,p1對(duì)象的__proto__屬性指向的是person構(gòu)造函數(shù)的原型對(duì)象。
如果使用new person()創(chuàng)建多個(gè)對(duì)象p1、p2、p3,則多個(gè)對(duì)象都會(huì)同時(shí)指向person構(gòu)造函數(shù)的原型對(duì)象。
我們可以手動(dòng)給這個(gè)原型對(duì)象添加屬性和方法,那么p1,p2,p3…這些對(duì)象就會(huì)共享這些在原型中添加的屬性和方法。
如果我們?cè)L問(wèn)p1中的一個(gè)屬性name,如果在p1對(duì)象中找到,則直接返回。如果p1對(duì)象中沒(méi)有找到,則直接去p1對(duì)象的__proto__屬性指向的原型對(duì)象中查找,如果查找到則返回。(如果原型中也沒(méi)有找到,則繼續(xù)向上找原型的原型—原型鏈)。
如果通過(guò)p1對(duì)象添加了一個(gè)屬性name,則p1對(duì)象來(lái)說(shuō)就屏蔽了原型中的屬性name。 換句話說(shuō):在p1中就沒(méi)有辦法訪問(wèn)到原型的屬性name了。
通過(guò)p1對(duì)象只能讀取原型中的屬性name的值,而不能修改原型中的屬性name的值。 p1.name = “小強(qiáng)”; 并不是修改了原型中的值,而是在p1對(duì)象中給添加了一個(gè)屬性name。
通過(guò)下面的程序來(lái)理解上面說(shuō)的內(nèi)容:
function person(name,age){ this.name = name; this.age = age; //在這里, 整個(gè)函數(shù)就是構(gòu)造函數(shù) } // 可以使用students.prototype 直接訪問(wèn)到原型對(duì)象 //給students函數(shù)的原型對(duì)象中添加一個(gè)屬性 name并且值是 "張三" person.prototype.hobby = "籃球"; person.prototype.email = "abc@163.com"; var p1 = new person("王小二",18); /* 訪問(wèn)p1對(duì)象的屬性hobby,雖然在p1對(duì)象中我們并沒(méi)有明確的添加屬性name,但是 p1的__proto__屬性指向的原型中有hobby屬性,所以這個(gè)地方可以訪問(wèn)到屬性hobby的值 注意:這個(gè)時(shí)候不能通過(guò)p1對(duì)象刪除hobby屬性,因?yàn)橹荒軇h除在p1中刪除的對(duì)象。 */ console.log(p1.hobby); // 籃球 var p2 = new person('王小二',19); console.log(p2.hobby); // 籃球 都是從原型中找到的,所以一樣。 console.log(p1.hobby === p2.hobby); // true