2.3原型模式
實際上,我們創(chuàng)建的每個函數(shù)都有一個prototype(原型)屬性豆巨。這個屬性是一個指針剩辟,它指向一個對象。而這個對象的用途是?包含可以由特定類型的所有實例共享的屬性和方法往扔。
按照字面意思來理解贩猎,prototype 就是 通過 構造函數(shù) ,而創(chuàng)建的對象實例的 原型對象萍膛】苑基本可以類比于java中類的概念。
使用原型對象的好處是可以讓所有對象實例分享它包含的屬性和方法蝗罗,而不必在構造函數(shù)中定義對象實例的信息艇棕。而是直接將他們添加在原型對象中,這與類的概念已經非常非常相似了串塑。
可以發(fā)現(xiàn)沼琉,page1和page2的方法相同,原因是二者的方法都取自原型對象的方法桩匪,而不是自己new一個出來
換句話說打瘪,page1和page2訪問了同一組屬性和同一個alert1函數(shù)。
1.理解原型的對象
任何時候傻昙,只要創(chuàng)建了新的函數(shù)闺骚,就會根據一組特定的規(guī)則創(chuàng)建一個prototype屬性。這個屬性指向函數(shù)的原型對象妆档。在默認情況下僻爽,所有原型對象都會自動獲取一個constructor(構造函數(shù))屬性,這個屬性包含一個指向prototype屬性所在函數(shù)的指針过吻。
如同上圖的例子:
Page是一個新函數(shù)? ==? >
page有一個prototype屬性? ==? >
Page.prototype指向原型對象? ==? >
原型對象包含一個指向prototype屬性所在函數(shù)(Page)的指針? ==? >
結論:Page.prototype.constructor = Page
創(chuàng)建一個自定義的構造函數(shù)后进泼,其原型對象只會擁有一個constructor屬性蔗衡,其他有關方法,都是從Object繼承而來乳绕。當使用構造函數(shù)創(chuàng)建實例后绞惦,實例的內部會包含一個指針,它指向構造函數(shù)的原型對象洋措,ECMA-262中管這個指針叫做[[Prototype]]济蝉,訪問時可以使用__proto__來訪問。
這個指針是用來連接實例與原型對象的菠发。
① 原型對象的constructor屬性指向構造函數(shù)
② 構造函數(shù)的prototype屬性指向原型對象
③ 實例的[[prototype]]指向原型對象
實際上我們可以發(fā)現(xiàn)王滤,兩個實例person1和person2中都不包含具體的方法sayName(),但是我們卻可以調用person1.sayName(),這是通過查找對象屬性的過程來實現(xiàn)的滓鸠。
檢查一個實現(xiàn)與原型對象是否存在關系可以使用原型對象.isPrototype()
當一個實例的[[Prototype]]指向調用isPrototype()的原型對象時雁乡,這個函數(shù)就會返回true:
//p1 是 實例??
//Person函數(shù) 是 構造函數(shù)??
//Person.prototype 是 原型對象
原型對象的isPrototypeOf(實例) = true
Person.prototype.isPrototypeOf(p1) = true
另外有一個新方法使得我們可以通過實例獲取原型對象:Object.getPrototypeOf(實例)
獲取到原型對象之后,我們便可以訪問原型對象中自定義的屬性的值糜俗,也可以更改原型對象中自定義的屬性的值踱稍。
每當代碼讀取某個實例的某個屬性時,都會執(zhí)行一次搜索悠抹,搜索目標時給定名字的屬性珠月。首先從實例本身開始,如果在實例中找到具有給定名稱的屬性楔敌,則返回啤挎;如果沒有找到,則搜索指針指向實例的原型對象卵凑,如果在原型對象中找到具有給定名稱的屬性庆聘,則返回;否則就會報錯:并沒有定義該屬性氛谜。
說白了掏觉,當我們訪問一個屬性時,它會先問:
實例有這個屬性嗎值漫?有-返回,沒有-繼續(xù)請問實例的原型對象织盼。
實例的原型對象有這個屬性嗎杨何? 有-返回,沒有-報錯沥邻。
因此危虱,如果在原型對象和實例中定義了命名相同的值,那么訪問實例的時候唐全,只會返回實例中定義的值埃跷。這并不是說你通過為實例的屬性賦值而更改了原型對象中的某個屬性值蕊玷,而是在搜索時第一次提問便拿到了結果,所以根本就沒有執(zhí)行第二次提問弥雹。
如果我們想重新訪問實例對應的原型對象中的某個屬性的話垃帅,就可以i使用delete 實例.屬性,這樣就能清除實例中的屬性值剪勿,進而訪問原型對象中的屬性了贸诚。