上一篇講了
①原型物件是什麼;
②__proto__
、prototype
、constructor
的關係;
③原型物件的作用;
④原型物件帶來的一些需要注意的問題;
沒理解的可以再複習一下。 傳送門:JS基礎—原型物件的那些事(一)
今天講一下原型鏈以及原型鏈的關係圖。
原型鏈是什麼
每個物件都有一個__proto__
屬性,指向物件的原型。
ps:準確的說,是每一個例項都有一個[[Prototype]]
屬性,指向原型物件。這是一個隱式屬性,存在但是我們的指令碼訪問不到,不過瀏覽器廠商大部分都支援一個__proto__
屬性,用來顯示指向原型,雖然能用,但__proto__
不是ECMA中的規範。
原型的值可以是一個物件,也可以是null
。如果它的值是一個物件,那麼這個物件也一定有自己的原型。這樣就形成了一條線性的鏈,我們稱之為原型鏈。
當我們在物件上呼叫一個屬性或者方法時,會先在這個物件上尋找,沒有的話就去它的原型物件上找,原型物件上沒有就去原型物件的原型物件上找,一直找到原型物件為null
為止,沒有的話就是undefined
。
簡而言之,物件尋找一個屬性會沿著原型鏈向上尋找,直到原型鏈的頂端。
還是以上一篇的Person
為例
function Person(name) {
this.name = name
}
Person.prototype.sayName = function() {
console.log(this.name)
}
var person = new Person("張三")
複製程式碼
我們先來畫一個簡單的關於原型的關係圖
以上是例項、建構函式和原型物件三者的關係圖。
PS: prototype
只是建構函式上的一個屬性,它是一個指標,指向原型物件,並不表示Person.prototype就是原型物件。這裡將Person.prototype
認為是原型物件,是為了方便理解,需要注意哦。
看不懂的同學去複習上一篇的內容,看懂的我們繼續。
注意點一
原型物件也是物件,是物件就有
__proto__
屬性,指向它的原型物件。
在上一個例子中,Person.prototype
就是一個物件,這個物件可以說是原生Object
建構函式的例項,所以
Person.prototype.__proto__ === Object.prototype
Object.prototype
也是一個物件,所以它也有__proto__
屬性,不過它的__proto__
指向null
,也就是原型鏈的頂端,再往上就沒有了。
重新補充一下關係圖
看懂的我們繼續
注意點二
任何函式都可以說是原生
Function
建構函式的例項。
所以Person
建構函式是Function
建構函式的例項。
Person.__proto__ === Function.prototype
複製程式碼
繼續我完善我們的關係圖
可能有人疑惑,Person
不是函式嗎,函式怎麼也有__proto__
,函式不是隻有prototype
嗎?
因為函式本質也是物件啊,在JS的世界裡,萬物皆物件,所以函式有__proto__
沒毛病。
注意點三
Function.prototype
也是物件,所以和Person.prototype
一樣,Function.prototype
可以說是原生Object
建構函式的例項,所以
Function.prototype.__proto__ === Object.prototype
複製程式碼
補充我們的圖(紅色的線)
注意點四
Function
和Object
都是建構函式,根據第二點任何函式都可以說是原生Function
建構函式的例項,那麼
Function.__proto__ === Function.prototype
Object.__proto__ === Function.prototype
複製程式碼
完善我們的圖(藍色的線),大功告成。
恩,就是這麼神奇,Function
是Function
的例項。。。
以上就是原型鏈的關係圖,將這個圖弄懂,原型物件的知識基本就掌握了。
雖然在真實場景中,這些知識用到的沒這麼複雜,但是掌握了最基礎的知識,將來出現問題時,就能更快的找到問題的原因。
對於新手而言,原型鏈和作用域鏈經常搞混,this和靜態作用域不知道在場景中怎麼使用,確實是很頭疼的問題,但這也許就是js的魅力所在吧。