JavaScript中原型這個概念很經常被提起,那麼它到底是什麼呢,它又有什麼用呢?接下來讓我們一步一步來理解它。
認識原型
原型的概念
在JavaScript中,原型也是一個物件,通過原型可以實現物件的屬性繼承,JavaScript的物件中都包含了一個[[Prototype]]
內部屬性,這個屬性所對應的就是該物件的原型。
原型訪問器
[[Prototype]]
作為物件的內部屬性,是不能被直接訪問的。不過我們可以通過下面這幾種方式來獲取到原型。
- __proto__
- Object.getPrototypeOf
- obj.constructor.prototype
那麼可能會有人疑惑,平時我們可以通過函式的prototype
屬性來獲取物件原型,這個又是怎麼回事?好吧,讓我們看個例子。
function Foo () {}
const f1 = new Foo()
const f2 = new Foo()
複製程式碼
從上面的圖我們可以看出f1
和f2
物件的__proto__
屬性是指向原型物件的Foo.prototype
。
同時這邊也回答了為什麼函式的prototype
可以獲取到物件原型,這是因為函式中有prototype
這個屬性,它是指向原型物件的。
原型物件中也有constructor
屬性指向Foo
這個建構函式。所以可以用第三種方式來獲取到物件原型,不過這個方法不可靠,因為屬性可以變嘛。
總結下:
每個建構函式都有一個原型物件(prototype),原型物件都包含一個指向建構函式的指標(constructor),而例項都包含一個指向原型物件的內部指標(proto)。
這邊丟擲兩個問題:
- 上面說到原型也是一個物件,那麼它肯定也有原型的,它的原型又是指向什麼呢?
Foo
函式也是一個物件,它的原型指向哪裡呢?
要想回答這兩個問題?這邊要引入一個概念原型鏈
原型鏈
原型鏈概念
原型鏈作為實現繼承的主要方法,其基本思想是利用原型讓一個引用型別繼承另一個引用型別的屬性和方法。
例項分析
還是Foo
函式來舉例子吧。
Function Foo () {}
const f1 = new Foo()
const f2 = new Foo()
const o1 = {}
const o2 = {}
複製程式碼
先來看下上面的第一個問題:
從這個原型鏈圖中可以看出Foo.prototype
這個物件的原型是Object.prototype
。這個也應驗了所有物件都繼承自Object.prototype
。
這邊還可以看到Object.prototype
原型是指向null
的。
接下來來看下第二個問題:
從上圖可以看到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
複製程式碼