本系列文章的第一篇中提到了對象類型,對象是 JavaScript 中的重要角色之一,本篇便從原型這個知識點切入,但願你們在閱讀過本篇文章以後腦海中都可以創建起一張完整的思惟導圖。瀏覽器
首先咱們要肯定一點,函數是一種可調用的對象,也在本系列第一篇中曾提到過,咱們能夠作以下校驗:bash
(()=>{}) instanceof Object // true
複製代碼
其次咱們要肯定,對象都是經過函數建立的,好比咱們平時寫的對象字面量,其實只是 new Object()
之類的語法糖而已。函數
知道以上兩點以後,咱們能夠說,函數是一種對象,對象又是經過函數建立,因此對象建立對象。是否會以爲有點不明覺厲的感受?其實要弄清楚它們之間的關係,不用去管這些彎彎繞。post
只要再明白一點,JavaScript 中除了 Object
,還存在一個角色,那就是 Function
。學習
咱們先來看一下在瀏覽器控制檯打印出 Object
和 Function
的結果:spa
> Object
<· ƒ Object() { [native code] }
> Function
<· ƒ Function() { [native code] }
複製代碼
原型屬於 JavaScript 的核心,咱們一步步來分析,瞭解原型的方方面面。prototype
prototype
和 [[Prototype]]
咱們知道函數是可調用對象,既然是對象,函數也是屬性的集合。這些屬性中其中一個就是 prototype
屬性,也就是咱們一般所說的原型。全部函數都有 prototype
屬性 (Function.prototype.bind()
例外)。而 prototype
是一個對象,它有個 constructor
屬性指向這個函數。這裏用思惟導圖表示出來,你們能夠自行在瀏覽器窗口打印相關信息來印證。code
從上圖能夠很清楚看出 function Foo()
與 Foo.prototype
的關係,同時咱們會看到實例對象 foo
有一個 __proto__
屬性指向 Foo.prototype
。__proto__
咱們稱爲隱式原型,只是對象內置屬性[[Prototype]]
的非標準實現,雖然瀏覽器都支持可是不推薦使用。cdn
下文爲方便表達理解,[[Prototype]]
內置屬性會用 __proto__
表示。對象
ES6中推薦使用
Object.getPrototypeOf()
方法來返回一個對象的[[Prototype]]
,使用Object.setPrototypeOf()
方法來設置一個對象的[[Prototype]]
。
咱們知道 Foo.prototype
也是一個對象,那它的 __proto__
指向哪裏呢?
咱們知道 function Object()
也是函數,因此它和普通構造函數擁有一樣的規則,不一樣點在於,Object.prototype
位於原型鏈頂端,看圖:
由上圖可知,Foo.prototype
的 __proto__
指向了 Object.prototype
, Object.prototype
也是一個對象,它的 __proto__
指向了 null
,這應該好理解,意思就是到頂了。
是時候解開謎團了,上文也提到 function Function()
也是函數,是否是和 function Foo()
和 function Object()
適用一樣的規則呢?答案是確定的,看下圖:
這裏除了上面的規則,咱們還應注意到幾個點:
function Foo()
、 function Object()
的 __proto__
屬性都指向了 Function.prototype
,這說明函數都是經過 Function
構造函數 new
出來的 ;function Function()
是個例外,雖然它的 __proto__
也指向了Function.prototype
,可是是引擎先內建了 Function.prototype
, 而後纔有 function Function()
,因此並非本身建立本身;Function.prototype
的 __proto__
指向了 Object.prototype
,是由於引擎先建立 Object.prototype
,再建立 Function.prototype
,並將二者用 __proto__
聯繫起來。上面的圖已經畫出了一條條的箭頭指向的鏈條,經過 __proto__
屬性鏈接,這就是原型鏈。
具體的能夠理解爲:當尋找一個對象的某個屬性時,若是沒有找到,則會順着 __proto__
屬性指向的原型對象上查找,一直往上直到 Object.prototype
,這一條查找的線路就被稱之爲原型鏈。
爲方便理解,總結必不可少:
Object.prototype
和 Function.prototype
是兩個特殊對象,由引擎建立,因此不用糾結這倆對象怎麼來的了;__proto__
屬性找到 Object.prototype
,Object.create(null)
創造出的對象例外,由於沒有 __proto__
屬性;__proto__
屬性找到 Function.prototype
;new
出來的,除了上面兩個特殊對象;prototype
是對象,它有個 constructor
屬性指向構造函數自己;__proto__
指向原型, __proto__
將對象和原型鏈接起來組成了原型鏈。你或許會問,直到這些有什麼用呢?那就涉及到類和繼承方面的問題了,下篇再見!
寫做是一個學習的過程,嘗試寫這個系列也主要是爲了鞏固 JavaScript 基礎,並嘗試理解其中的一些知識點,以便能靈活運用。本篇同步發佈在「端技」公衆號,若是有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝!
整個系列會持續更新,不會完結。