js奧義:原型與原型鏈(1)
- 2019 年 11 月 2 日
- 筆記
要弄懂原型鏈,首先應先明白prototype原型對象、__proto__、對象三者之間的關係。
引入構造函數的相關定義:
構造函數是一種比較特殊的函數,用於批量實例化對象。通俗一點說,構造函數是用於生成對象的模板。
由於工廠模式在實例化對象時會存在同一功能程式碼在記憶體中開闢不同記憶體空間從而造成記憶體空間浪費的問題,更多的人選擇使用構造函數來實例化對象,es6中引進的class關鍵字正是基於構造函數的思想
構造函數的本質上是將對象中一些公共的方法和屬性 抽取出來,然後將這個函數封裝成可復用的構造函數.
構造函數的特點(與工廠函數相比較):
a. 函數名首字母大寫;
b. 函數體內沒有關鍵字new,在實例化一個對象時會使用關鍵字new;
c. 構造函數體內的this指代當前實例化對象;
d. 函數體內沒有關鍵字return。
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對象!
這樣,就具備了深入理解原型鏈的條件。