以前對JS的prototype知識比較模糊,今天理清了記下來,以防忘記,直切正題:javascript
1.要明白原型鏈,就必須先清楚JS的構造函數模式:html
js是面向對象的語言,既然是面型對象,就必定會有一個對象的模板,Java中用"類"來做爲對象的模板,而JS中,能夠用構造函數來做爲對象的模板,你能夠認爲至關於Java中的"類",java
寫法以下所示:函數
function Cat(name,color){ this.name=name; this.color=color; } var c = new Cat();
Cat函數就是構造函數,構造函數中的this指向的就是當腳本運行時Cat所生成的實例,若是把構造函數當作類,就會輕鬆許多。this
緊接着下面一句var c = new Cat();就是根據構造函數生成相應的對象,相似於JAVA中根據類生成實例對象同樣。spa
這就是JS中面向對象的構造器模式。prototype
2.明白了構造函數模式,來看看構造函數模式的弊端以及如何解決:code
咱們能夠根據構造函數來建立N個對象,每一個對象有本身的內存空間。咱們來思考這麼一個問題:若是構造函數中有兩個固定值的屬性,當咱們用這個構造函數去建立對象的時候,每一個對象都會在本身的內存空間中存放這個固定值的屬性,這就形成了沒必要要的浪費,對吧?想想JAVA是否是也存在這種狀況?是存在的,那JAVA怎麼解決的?對,繼承!htm
在JAVA中咱們會將一些對象存在共性的地方,抽取出來存放到Super類中;在JS中對於每個構造函數都有這麼一個額外的對象,用來存放一些共有的東西,是否是很父類很像?這個額外的對象就是原型對象,一個原型對象對應一個構造函數,也就是說一個構造函數只有一個原型對象,例如構造函數Object,就對應一個原型對象,構造函數Obejct的prototype屬性指向他所對應的原型對象,而Object構造器生成的實例對象都有一個__proto__屬性,也只想Obejct構造器所對應得原型對象,這樣就實現了節省內存的目的。以下代碼:對象
function Cat(name,color){ this.name = name; this.color = color; } Cat.prototype.type = "貓科動物"; Cat.prototype.eat = function(){alert("吃老鼠")};
3.明白了原型的概念,再來看看原型鏈的概念:
要清楚在構造函數模式中有幾個角色:構造函數、實例對象、原型對象。 在這三個對象之間,他們的關係是怎樣的?先來理一理。
如上圖所示,A表明構造函數,它持有一個prototype屬性,指向他所對應的原型對象A.prototype,而A.prototype持有constructor屬性指向A構造函數,以此來造成一對一的關係,而new A()表明着根據A構造函數來生成的實例對象,new A()持有一個__proto__屬性,指向A所對應的原型對象,以此來實現多個實例對象共享原型對象中的固定狀態的某些變量。
因此總結一下:構造函數中有一個prototype屬性、原型對象有一個constructor屬性、實例對象中有一個__proto__屬性。
剛纔好像落下一個,就是原型對象中除了constructor屬性外,其實還有一個__proto__屬性,這個怎麼理解?若是你把原型對象當作一個實例對象,是否是他也能夠從其餘的原型對象中共享數據?這就是了,原型對象中的__proto__就是構成原型鏈的關鍵,你能夠理解成繼承鏈。
咱們都知道JS是面向對象,那就不可避免的JS存在一個上帝級別的對象,就是Obejct,全部的一切對象來源於它,什麼意思呢?
其實上面的A構造器所對應的原型對象中的__proto__指向就是Object的原型對象,因此能夠向相面的圖這樣理解:
補充一點:其實構造函數其實也是一個對象對吧?那麼它是那個構造函數構造出來的呢?固然是Function,因此說構造函數做爲一個函數實例對象,也持有__proto__屬性,並指向Function.prototype。