原型
1.原型的定義:原型是function對象的一個屬性,它定義了構造函數製造出來的對象的公共祖先。經過該構造函數產生的對象,能夠繼承該原型的屬性和方法。原型也是對象。函數
咱們先定義一個構造函數,Person.prototype這個屬性就是這個構造函數的原型,這個屬性是天生就有的,而且這個屬性的值也是一個對象。測試
咱們能夠在prototype上面添加屬性和方法,每個構造出來的對象均可以繼承這些屬性和方法。this
雖然每個對象都是獨立的,可是他們都有共同的祖先,當咱們訪問這個對象的屬性的時候,若是它沒有這個屬性,就會向上找到它的原型,而後在原型上訪問這個屬性。spa
這裏咱們oPerson對象由於自身有一個money屬性,因此就不會到原型上去尋找money屬性,而是查詢自身的money屬性,所以打印的是100,可是當咱們刪除了自身的money屬性以後,它就會到原型上去尋找money這個屬性,所以就打印200。prototype
當咱們再次給對象添加屬性以後,打印money屬性就是自身的屬性。3d
2.利用原型特色和概念,能夠提取公有屬性。對象
咱們能夠把每個對象都有的公有屬性不寫在構造函數裏面,而是提取到原型上,這樣當咱們用構造函數構造大量的對象的時候就不須要走屢次構造函數裏面的賦值語句了,而只須要走一遍,每個對象調用屬性的時候直接上原型上查找就能夠了。blog
3.對象如何查看原型繼承
前面咱們提到了構造函數能夠經過.prototype的方法來查看構造函數的原型,那麼咱們怎麼查看對象的原型呢?原型鏈
咱們前面提到過用構造函數構造對象的時候,會隱式建立一個this對象,這個this對象裏面有一個默認的屬性叫作proto屬性,這個屬性的值就是指向的這個對象的原型。
當查找的屬性是自身沒有的屬性的時候,就會先查找proto這個屬性,而後這個屬性指向了原型,因此就到原型上面繼續查找屬性了。
注意:prototype是函數的屬性,proto是對象的屬性。
4.對象如何查看構造自身的構造函數
在prototype裏面,有一個隱式的屬性叫作constructor,這個屬性記錄的就是對象的構造器,裏面存的就是構造函數。
console.log(oPerson.constructor); // Person();
原型鏈
有了原型,原型仍是一個對象,那麼這個名爲原型的對象天然還有本身的原型,這樣的原型上還有原型的結構就構成了原型鏈。
Foo創造出來的每個對象都繼承自grandfoo這個對象,son的每個對象都繼承自father這個由Foo創造出來的對象,這樣son就能夠繼承上面Foo和Gra的全部屬性。
當咱們查找son上的屬性的時候,若是son自身有屬性,那麼就打印出來,若是沒有,就向上查找原型father,若是father上面還有這個屬性,那麼繼續向上查找grandfoo,若是有就輸出,若是沒有就返回undefined。
這種鏈式的查詢結構就叫作原型鏈。
那麼原型鏈有沒有終點?咱們寫的Gra是否是這個原型鏈的終點?
有測試能夠看出,其實咱們的Gra.prototype上面還有原型,這個原型是一個空對象,這個空對象上面就沒有了。
其實,絕大部分的對象最終都會繼承自Object.prototype這個對象。
咱們沒有規定原型的對象,它們的原型就是Object.prototype。
因而可知,原型鏈的終點通常是Object.prototype;
可是並非全部的對象都有原型。
咱們上一篇提到過第三種構造對象的方法,使用Object.create方法。
Object.create()方法須要寫一個參數,這個參數就是咱們這個對象的原型。若是咱們想要構造和var obj = {};同樣的空對象,那麼就須要寫:
固然,咱們也能夠寫一個自定義的屬性,讓它成爲原型。
可是,當咱們寫參數爲null的時候,咱們就構造出來了一個沒有原型的對象。
undefined null也都沒有原型。它們之因此能打印出來,是由於不調用任何方法的,直接打印出來。
原型鏈上屬性的增刪改查
其實咱們前面一直在使用着這些方法,這裏說一下原型上的引用值。當咱們經過一個對象改變了原型上的引用值類型的屬性的話,那麼全部對象的這個屬性的值都會隨之更改。
刪除
這個時候person對象上面沒有了name屬性,那麼依據咱們前面說的當自身沒有這個屬性的時候就會向原型查詢這個屬性的說法,咱們再次刪除這個屬性是否是就能夠刪除原型上的屬性了?
然而事實並無,因而可知,對象並不能刪除原型上的屬性。
這裏提一下這個this的指向。誰調用這個方法,這個方法中的this就指向這個調用它的對象。
因此這裏的this指向的是oPerson這個對象,這個對象的name屬性值是son。
那麼今天的知識點就介紹到這裏喲~