要弄懂原型鏈,首先應先明白prototype原型對象、__proto__、對象三者之間的關係。javascript
引入構造函數的相關定義:java
構造函數是一種比較特殊的函數,用於批量實例化對象。通俗一點說,構造函數是用於生成對象的模板。es6
因爲工廠模式在實例化對象時會存在同一功能代碼在內存中開闢不一樣內存空間從而形成內存空間浪費的問題,更多的人選擇使用構造函數來實例化對象,es6中引進的class關鍵字正是基於構造函數的思想瀏覽器
構造函數的本質上是將對象中一些公共的方法和屬性 抽取出來,而後將這個函數封裝成可複用的構造函數.函數
構造函數的特色(與工廠函數相比較): this
a. 函數名首字母大寫;spa
b. 函數體內沒有關鍵字new,在實例化一個對象時會使用關鍵字new;prototype
c. 構造函數體內的this指代當前實例化對象;對象
d. 函數體內沒有關鍵字return。blog
function Fn() { this.n = 20 } Fn.prototype.say= function() { console.log(this.n) } var deb = new Fn()
構造函數的new關鍵字在實例化對象時會作如下四件事:
a.如今內存中開闢一塊內存空間(new obj);
b.讓構造函數體內的this指向這個對象 (於是,this指代當前對象);
c.將構造函數體內的屬性和方法賦值給這個這個對象;
d.返回這個對象 (於是,構造函數體內沒有return關鍵字)
爲了區別對待,如下將構造函數稱爲父類,將實例化對象稱爲子類。
一:原型
1.定義
每個函數身上都有一個prototype(原型),因爲這個prototype的值是一個對象類型,於是又叫作原型對象,ptototype屬性是函數獨有的屬性!
2.原型的做用
原型對象的做用一般用來共享父類的方法,因爲方法是函數,本質上也是一個對象,而對象的內存地址保存在堆空間裏,如同工廠模式通常,多個內存空間存放相同的代碼,會形成大量空間被佔用,於是將公有的方法添加在父類的prototype上,也就是寫入了同一對象上,調用的時候也就避免了多個空間存放同一代碼的錯誤示範,而因爲父類的屬性的值是基本類型,所佔內存較少,因此咱們每每將其添加到父類函數體的內部。
function Fn() { this.n = 20 } Fn.prototype.sing = function() { console.log(this.n) } var deb = new Fn() var deb2 = new Fn() console.log(deb.sing === deb2.sing) //true
二:__proto__
與函數的prototype屬性不一樣,每個obj的對象都有一個__ptoto__屬性,這個__proto__屬性隱式的指向了這個子類的的構造函數的prototype屬性!可是這個__proto__屬性是不可見的,這也就是爲何將其稱做是隱式的,不過好在瀏覽器的支持下,它被定義爲__proto__
若是看到這裏,但願你再好好思考一下 」萬物皆對象「這句話的含義
從父類的角度看,子類的_proto_屬性隱式指向了它的父類的prototype對象;從子類的角度看,子類自身的__proto__屬性指向了它的父類的prototype屬性
假如咱們對比父類的prototype與子類的__proto__屬性:
console.log(Fn.prototype === deb.__proto__)//true
理解了這一點,就能夠明白爲何構造函數添加在其原型對象上的方法,實例化對象能夠共享使用了:由於構造函數的prototype屬性指向的 與 實例化對象的__proto__屬性指向的 是同一個對象,也就是父類的prototype對象!
這樣,就具有了深刻理解原型鏈的條件。