一題搞懂原型鏈

原型鏈類型的題在面試中屬於高頻考點,下面用一個經典的面試題還原js中原型鏈的真面目。javascript

請問:f有方法a和方法b嗎?java

var F = function () {};
Object.prototype.a = function () {};
Function.prototype.b = function () {} ;
var f = new F()

在作這題以前,必定要了解js中原型鏈的一些繼承關係,把那種繼承關係圖記在腦子裏,而後看到題目後把各自一一對應尋找繼承關係,以前走過彎路,初學js時在網上找原型鏈的圖,又複雜又記不住,相似這種:
201622785912987.jpg
不要看了,反正我是看不下去。面試

正言

在js中,對象都有__proto__屬性,通常這個是被稱爲隱式原型,該隱式原型指向構造該對象的構造函數的原型。
函數比較特殊,它除了和其餘對象同樣有__proto__屬性,還有本身特有的屬性----prototype,這個屬性是一個指針,指向一個包含全部實例共享的屬性和方法的對象,稱之爲原型對象。原型對象也有一個constructor屬性,該屬性指回該函數。segmentfault

按照上述的理論能夠把構造函數(函數)、對象(構造函數new出來的)、Object(頂層的對象)之間的大概關係串起來。相似以下:
原型鏈.jpg函數

這張圖是我在吳華的javascript高級進階課程中看到的截圖,受用至今。
記住這四個最主要的點就ok了,對照上圖理解記憶:spa

  1. 對象都有個隱式原型__proto__),它指向構造函數的原型對象(prototype)。
  2. 構造函數的原型對象也有個隱式原型__proto__)它指向Object的原型對象(prototype).
  3. Object的原型對象有個constructor指向Object自己。
  4. 構造函數的constructor指向構造函數自己。

這裏看完你就能明白對象上的toString()或者valueof()是怎麼來的了,打印一下Object的原型對象,就能獲得結果,你去訪問對象的屬性(包括方法),他會先找自身有沒有這個屬性,沒有的話會沿着原型鏈一層一層往上找,例如上圖,我要訪問objshowAge方法,他自己有,返回他自己的showAge方法,要訪問showUserNameobj沒有,會沿着隱式原型去看看構造函數的原型對象有沒有,有的話返回,沒有的話繼續去Object的原型對象去找,依次往上。這也不難理解爲何對象上都有toString()方法了。prototype

解題思路

理解原型鏈後,再回到最初的那道面試題:指針

  1. 首先,f是什麼?
    f是構造函數F new出來的對象,按照上面我說的,對象都有個隱式原型,它指向構造函數的原型對象,即f的__proto__指向F.prototype。
  2. 沿着原型鏈,F.prototype.__proto__指向Object.prototype,即得出第一個答案了,f能夠取到a方法,因爲f的原型鏈上沒通過Function.prototype,Function.prototype是Object.prototype建立的,只能沿着_proto_向上找因此取不到b方法。
  3. 函數都是由Function new出來的,這裏你能夠把它當成一個被另外一個構造函數new出來的普通對象,因此F這個構造函數的隱式原型也指向了Function的原型對象,即F.__proto__指向Function.prototype,因此F函數能夠取到b方法(可能有點暈,下面會解釋)

Function

在 JavaScript 中,用 new 關鍵字來調用的函數,稱爲構造函數。構造函數首字母通常大寫

那我理解的是理論上任何一個函數均可以當成一個構造函數。
其實上面的原型圖還有一部分Function的沒畫出來。
瞭解這個以前,帶着另外一個面試題去思考:
原型鏈頂層是什麼?按照上面的圖你可能會認爲是Object或者Object.prototype,其實不是。
注意:code

要理解原型鏈頂層要和原型鏈其餘地方的理解有一些不一樣,這裏Object和Function及其原型要分開看,不能將原型和自己看做是理所固然的關係
  1. Object.prototype和Object的關係
    Object.prototype是JS世界中最先生成的,理論上有了原型(Object.prototype)就會有自己(Object),然而Object的內容倒是由Function構成的。用通俗一點的話來解釋就是,有了Object.prototype就有了Object的肉體,然而Object的靈魂倒是由Function構成的。
  2. Object.prototype.__proto__
    Object.prototype是由上層對象建立的 (一些靜態語言,像C++和Java),在這裏爲了避免引發誤會將其指向了null

頂層圖.png

總結原型鏈頂層關係

  1. Object.prototype是由上層對象建立的 (一些靜態語言,像C++和Java),在這裏爲了避免引發誤會將其指向了null
  2. Object.prototype創造了Function.Prototype
  3. Function.prototype創造了Function
  4. Object創造了其餘對象(window, document, 自定義對象)
  5. Object是Function的一個實例
  6. 任何函數繼承自Function.prototype
  7. 任何對象最終繼承自 Object.prototype
相關文章
相關標籤/搜索