玩轉 JavaScript 之不得不懂的原型

概述

本系列文章的第一篇中提到了對象類型,對象是 JavaScript 中的重要角色之一,本篇便從原型這個知識點切入,但願你們在閱讀過本篇文章以後腦海中都可以創建起一張完整的思惟導圖。瀏覽器

函數與對象的關係

首先咱們要肯定一點,函數是一種可調用的對象,也在本系列第一篇中曾提到過,咱們能夠作以下校驗:bash

(()=>{}) instanceof Object   // true
複製代碼

其次咱們要肯定,對象都是經過函數建立的,好比咱們平時寫的對象字面量,其實只是 new Object() 之類的語法糖而已。函數

知道以上兩點以後,咱們能夠說,函數是一種對象,對象又是經過函數建立,因此對象建立對象。是否會以爲有點不明覺厲的感受?其實要弄清楚它們之間的關係,不用去管這些彎彎繞。post

只要再明白一點,JavaScript 中除了 Object ,還存在一個角色,那就是 Function學習

咱們先來看一下在瀏覽器控制檯打印出 ObjectFunction 的結果: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.prototypeObject.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,這一條查找的線路就被稱之爲原型鏈。

總結

爲方便理解,總結必不可少:

  1. Object.prototypeFunction.prototype 是兩個特殊對象,由引擎建立,因此不用糾結這倆對象怎麼來的了;
  2. 對象都能經過 __proto__ 屬性找到 Object.prototypeObject.create(null) 創造出的對象例外,由於沒有 __proto__ 屬性;
  3. 函數都能經過 __proto__ 屬性找到 Function.prototype;
  4. 對象都是函數 new 出來的,除了上面兩個特殊對象;
  5. 函數的 prototype 是對象,它有個 constructor 屬性指向構造函數自己;
  6. 對象的 __proto__ 指向原型, __proto__ 將對象和原型鏈接起來組成了原型鏈。

你或許會問,直到這些有什麼用呢?那就涉及到類和繼承方面的問題了,下篇再見!

玩轉 JavaScript 系列

寫做是一個學習的過程,嘗試寫這個系列也主要是爲了鞏固 JavaScript 基礎,並嘗試理解其中的一些知識點,以便能靈活運用。本篇同步發佈在「端技」公衆號,若是有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝!

整個系列會持續更新,不會完結。

全目錄

1. 玩轉 JavaScript 之 數據類型

2. 玩轉 JavaScript 之不得不懂的原型

相關文章
相關標籤/搜索