一漓糙、什么是原型和原型鏈
我們先來看一個簡單的例子,首先我們定義一個Number()函數(shù)
var n1 = new Number(1)
這個時候我們就可以調(diào)用Number()函數(shù)的各種方法了胖烛,比如 toString()
n1.toString()
我們知道基本類型對象是存在棧內(nèi)存中的悔耘;復雜類型對象存在堆內(nèi)存中,棧內(nèi)存中只存其地址(指針)
所以此時 n1 如果要調(diào)用 toString() 方法的話翩活,必須有一個指針能指向這個對象逐哈。那么 toString() 這個方法存在哪里比較好呢芬迄,最基本的想法當然是存在 Number() 函數(shù)中好了
這樣調(diào)用當然不會有什么問題,但是如果此時我們再來一個
var n2 = new Number(2)
同是也調(diào)用 n2 的toString()方法
n2.toString
那此時我們就發(fā)現(xiàn)有一個問題昂秃,n1 和 n2 都有一個toString() 方法禀梳,如果在棧內(nèi)存中各自存儲一個toString() 的方法的話,很明顯比較浪費肠骆,當數(shù)據(jù)量變大時就會明顯影響性能算途。
所以,我們是不是能將toString() 這類大家都有可能會用到的方法打包放在一個對象內(nèi)蚀腿,然后在Number() 函數(shù)放一個指針不就好了嘴瓤,那就給這個指針取個名字吧,就叫__proto__
吧
從圖中我們可以看到,Number(1) 中的有一個預(yù)設(shè)屬性
__proto__
廓脆,里面包含了 toString() 在內(nèi)的好幾個有關(guān)數(shù)值的方法筛谚。那無關(guān)數(shù)值的方法,有關(guān)對象的方法呢
hasOwnProperty()
,眼尖同學已經(jīng)發(fā)現(xiàn)了停忿,在Number() 的__proto__
中還有一個__proto__: Object
,就像你所看到的一樣驾讲,這里指向的就是對象的通用方法写半。
這里我們就你能看到n2.__proto__
和 Number.prototype
是一樣的,證明n2.__proto__
指向的就是Number.prototype
氧枣。
同理:
n2.__proto__.__proto__ === Object.prototype
也是true這里我們就能推廣得到一個比較通用的法則 對象.__proto__ = 函數(shù).prototype
例如:
String.__proto__ === Function.prototype \\true
Number.__proto__ === Function.prototype \\true
Function.__proto__.__proto__ === Object.prototype \\true
這個時候需要給這整個做法取個名字了,由于這些個公用屬性一個指向一個别垮,要是畫出箭頭指針便监,就像鏈子一樣,那就要原型鏈吧碳想。這些指向的最后就是null烧董。
Object.prototype.__proto__ === null //true
二、原型鏈解決了什么問題
我們要說到一個新詞繼承胧奔,依舊是 var n2 = new Number(2)
逊移,我們沒有定義n2任何的屬性和方法,但是它卻能夠通過原型鏈調(diào)用Number.prototype龙填、甚至是Object.prototype 中的屬性和方法胳泉,這就是n2 繼承了符合它本身數(shù)據(jù)類型的公用屬性。
所以當試圖訪問一個對象的屬性時岩遗,它不僅僅在該對象上搜尋扇商,還會搜尋該對象的原型,以及該對象的原型的原型宿礁,依次層層向上搜索案铺,直到找到一個名字匹配的屬性或到達原型鏈的末尾。