關於原型鏈的知識,我剛開始就是看一篇一篇的博客,知識有點零碎,後面看了下《JS高級程序設計》,又大體整合了一下。下面記錄的是,對於一條完整的原型鏈長什麼樣這個問題的思考。javascript
借用一段在《JS高級程序設計》中的一段代碼:html
function Person(){} Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); person1.sayName(); //"Nicholas" var person2 = new Person(); person2.sayName(); //"Nicholas" alert(person1.sayName == person2.sayName); //true
此段代碼中,構造函數Person
,原型對象Person.prototype
以及實例對象person1
和person2
的關係以下圖所示:java
按照書上的解釋,很好理解,但很顯然,它並非一條完整的原型鏈,而且我也有疑問:書中給出的示例圖中沒有畫構造函數Person和原型對象Person.prototype的_proto_屬性。segmentfault
首先:_proto_
屬性是個對象都有,那麼,在萬物皆對象的JS中,構造函數Person
和原型對象Person.prototype
的_proto_
屬性又指向哪裏呢??其次,就這個問題,結合上面給出的代碼,能夠將一條完整的原型鏈用相似上面的圖畫出來嗎??函數
以前看了一篇博文,其中分析了_proto_
應該指向誰的問題,舉了下面這個例子,可能直接看會有點蒙圈,原文: JS原型鏈簡單圖解 - 最騷的就是你 - 博客園工具
對應的示例代碼以下:this
var A = function(){}; var a = new A(); console.log(a.__proto__); //A {}(A.prototype即A的原型對象) console.log(a.__proto__.__proto__); //Object {}(Object.prototype即Object的原型對象) console.log(a.__proto__.__proto__.__proto__); //null
其實,對於a._proto_ ==A.prototype
以及Object.prototype._proto_==null
比較好理解:.net
使用函數表達式方法建立的函數變量A,就是新的函數變量a的構造函數,因此a的原型對象就是其構造函數的prototype所指的對象:A.prototype
而Object.prototype._proto_爲何是null能夠參考:爲何原型鏈的終點是null,而不是Object.prototype?- 餘百鍊的博客 - CSDN博客prototype
然而,爲何A.prototype
的原型是Object.prototype
,即A.prototype._proto_==Object.prototype
怎麼解釋呢??設計
其實,原型鏈是指對象的原型鏈,這個鏈上的節點都是一級一級的原型對象,因此原型鏈上的全部節點都是對象!!!所以這就好理解了,A.prototype
是一個對象,而後它是Object
的一個實例,因此它的原型是Object.prototype
。
這裏須要注意的是,a雖然是原型鏈上的起點,它也是對象,可是它的原型並非直接就是Object.prototype,它的原型是其構造函數的prototype所指的對象:A.prototype
其實這個圖描述的還只是局部 ,不利於理解,請看下面的圖:(圖片取自javascript - 爲何原型鏈的終點是null,而不是Object.prototype - SegmentFault 思否 )
從這張大圖中咱們能夠看出來,
fun._proto_
)都是Function.prototype
,不管是JS原生的構造函數如Function仍是Object等仍是用戶自定義的構造函數如上圖的Foo;fun.prototype._proto_
)都是Object.prototype
,不管是自定義的仍是原生的(Object除外);根據這個圖,能夠更好的理解下面這兩句話:
_proto_
是任何對象都有的屬性,而JS裏萬物都是對象,因此會造成一條_proto_
連起來的鏈條,遞歸訪問_proto_
必須最終到頭,而且值是null;prototype
這樣的話,關係就比較明瞭了。因此,文章開頭的那段代碼的原型鏈應該以下圖所示:
function Person(){} Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); person1.sayName(); //"Nicholas" var person2 = new Person(); person2.sayName(); //"Nicholas" alert(person1.sayName == person2.sayName); //true
趁着這個機會,能夠討論一下原生構造函數Object
和Function
到底什麼關係?
從上圖中咱們能夠把Function
和Object
部分單獨摘出來:
Function._proto_==Function.prototype==function(){} Function._proto_._proto_==Object.prototype Function._proto_._proto_._proto_==Object.prototype._proto_==null Object._proto_ === Function.prototype==function(){} Object._proto_._proto_==Object.prototype Object._proto_._proto_._proto_==null
從上圖中能夠看到構造函數之間的關係以下:
Object.prototype.constructor===Object Object instanceof Function;//true Object.constructor===Function Function.prototype.constructor===Function Function instanceof Object;//true Function.constructor===Function