米娜桑,哦哈喲~
原型鏈,已是一個老生常談的話題了,這裏就不過多總結,精華一張圖就能夠搞定。該文章更多的是從 一個公式 的角度講述原型鏈。git
補充說明github
實例化:用類(class)建立對象(obj)的過程。
如:TensionMax = new Person()
,那麼 TensionMax
是 Person
的實例(對象)。
但因爲 JavaScript 並不存在類,因此 JavaScript 所謂的類,只是咱們模擬出來的函數,最終仍是基於原型構建。函數
如下 3 個觀點只是爲了更方便快捷地理解原型鏈,切勿對號入座。其中依然存在着先有雞仍是先有蛋的問題。對於單純的開發者來講,感興趣或者時間充裕的話能夠深究,已附上友情連接於本章結尾。this
先上結論prototype
一、obj.proto === class.prototype
知足此式子時,咱們能夠把 obj 稱之爲 class 實例出來的對象。code
二、obj 上屬性的查找會以 __proto__
鏈條的方式進行查找,直到爲 null
時終止。對象
三、以第 1 點爲理解導向,原型鏈的終點是 Object.prototype
。blog
這條就看成是一個公式。知足這一條,那麼咱們能夠把 obj
看成 class
實例出來的對象。
當咱們實例出 Person 即 let Tension = new Person()
,其中的關係圖以下:繼承
let Person = function (name, age) { this.name = name this.age = age this.race = 'human' } Person.prototype.country = 'China' console.log(Person.prototype) //輸出{country: 'China', constructor: Person}
也就是說 Person.prototype.constructor === Person
建立函數時,函數會自帶特有的屬性 prototype
。
而當實例 Person 時ip
let TensionMax = new Person('huang', 10) console.log(TensionMax) //{name: 'huang', age: 10, race: 'human'} console.log(TensionMax.country) //China console.log(TensionMax.__proto__.country) //China
換句話而言,new 操縱符 實際作了如下的事情。
let TensionMax = {} //即 new Object() TensionMax.__proto__ = Person.prototype Person.call(TensionMax) //call在這裏的做用是將 Person 的 this 值拷貝到 TensionMax 對象中。
也就是說,當實例化對象後,對象 TensionMax
和對應的類 Person
經過 __proto__
來連接。
根據上述的關係圖,若是一直根據 __proto__
這個鏈條查找,會有一個終點。
console.log(TensionMax.__proto__.__proto__.__proto__) //null (TensionMax.__proto__).__proto__ === Object.prototype //true
根據第 1 點的公式,TensionMax.__proto__
即 Person.prototype
爲 Object 函數這個類實例出來的對象。最終到達終點 Object.prototype
console.log(Object.prototype.prototype) //undefined console.log(Object.prototype.__proto__) //null
以第 1 點爲理解導向,原型鏈的終點是 Object.prototype
,那麼有以下關係:
Tension 爲 Person 的實例對象
Person 爲 Function 的實例對象
Person.prototype 爲 Object 的實例對象Function 爲 Function 的實例對象
Object 爲 Function 的實例對象
Function.prototype 爲 Object 的實例對象
根據第 1 點的公式,以 __proto__
箭頭爲導向能夠看出,先有 Object.prototype
,由之誕生 Function.prototype
,隨後纔有了 Function 和 Object。
那麼 Function 和 Object 誰先有,還有待深究。