JavaScript原型梳理

wuzhengyan2015發表於2018-05-12

JavaScript中原型這個概念很經常被提起,那麼它到底是什麼呢,它又有什麼用呢?接下來讓我們一步一步來理解它。

認識原型

原型的概念

在JavaScript中,原型也是一個物件,通過原型可以實現物件的屬性繼承,JavaScript的物件中都包含了一個[[Prototype]]內部屬性,這個屬性所對應的就是該物件的原型。

原型訪問器

[[Prototype]]作為物件的內部屬性,是不能被直接訪問的。不過我們可以通過下面這幾種方式來獲取到原型。

  • __proto__
  • Object.getPrototypeOf
  • obj.constructor.prototype

那麼可能會有人疑惑,平時我們可以通過函式的prototype屬性來獲取物件原型,這個又是怎麼回事?好吧,讓我們看個例子。

function Foo () {}
const f1 = new Foo()
const f2 = new Foo()
複製程式碼

JavaScript原型梳理

從上面的圖我們可以看出f1f2物件的__proto__屬性是指向原型物件的Foo.prototype

同時這邊也回答了為什麼函式的prototype可以獲取到物件原型,這是因為函式中有prototype這個屬性,它是指向原型物件的。

原型物件中也有constructor屬性指向Foo這個建構函式。所以可以用第三種方式來獲取到物件原型,不過這個方法不可靠,因為屬性可以變嘛。

總結下:

每個建構函式都有一個原型物件(prototype),原型物件都包含一個指向建構函式的指標(constructor),而例項都包含一個指向原型物件的內部指標(proto)。

這邊丟擲兩個問題:

  1. 上面說到原型也是一個物件,那麼它肯定也有原型的,它的原型又是指向什麼呢?
  2. Foo函式也是一個物件,它的原型指向哪裡呢?

要想回答這兩個問題?這邊要引入一個概念原型鏈

原型鏈

原型鏈概念

原型鏈作為實現繼承的主要方法,其基本思想是利用原型讓一個引用型別繼承另一個引用型別的屬性和方法。

例項分析

還是Foo函式來舉例子吧。

Function Foo () {}
const f1 = new Foo()
const f2 = new Foo()
const o1 = {}
const o2 = {}
複製程式碼

先來看下上面的第一個問題:

JavaScript原型梳理

從這個原型鏈圖中可以看出Foo.prototype這個物件的原型是Object.prototype。這個也應驗了所有物件都繼承自Object.prototype

這邊還可以看到Object.prototype原型是指向null的。

接下來來看下第二個問題:

JavaScript原型梳理

從上圖可以看到Foo函式的原型是指向Function.prototype的。

不知道你們有沒注意到,Function的原型也是指向Function.prototype的,還有Function.prototype指向Object.prototype

同時這邊可以看到Objcet也是由函式建立的,函式的原型鏈上又有Object.prototype,這邊好像有問題,Objcet沒被建立之前,函式原型鏈上為什麼會有Object.prototype

這邊有一種的解釋是:

先有 Object.prototype(原型鏈頂端),Function.prototype 繼承 Object.prototype 而產生,最後,Function 和 Object 和其它建構函式繼承 Function.prototype 而產生。

順便提下函式其實也有一個constructor屬性,它是指向Function的。

Foo.constructor === Function  // true
Array.constructor === Function // true
Function.constructor === Function // true
Object.constructor === Function // true
複製程式碼

講到這裡也差不多了,出一些題給大家看看。

function Foo () {}

typeof (Object) // function
typeof (Array) // function

Foo.constructor === Function // true
Function.constructor === Function // true

Object.prototype.constructor === Object // true
({}).__proto__ === Object.prototype // true

Object.__proto__ === Function.prototype // true
Function.__proto__ === Function.prototype // true

Object instanceof Function // true
Function instanceof Object // true

typeof Object.prototype // object
typeof Function.prototype // function
複製程式碼

參考資料

相關文章