你真的明白javascript中的原型和原型鏈了嗎

文章開頭說的話

首先你必須明白(或者記住)的JavaScript常識:瀏覽器

  1. 在JavaScript中每一個函數都有一個prototype屬性
  2. 在JavaScript中每一個對象都有一個__proto__屬性
  3. 在JavaScript中函數是一等公民,即函數也是對象

prototype和__proto__

prototype究竟是個啥呢?下面看下這段代碼,咱們慢慢來函數

// Animal是個構造函數,因此有prototype屬性
function Animal(){}
// 在prototype上定義eat方法
Animal.prototype.eat = function(food){
  console.log("it is eating " + food);  
}
// 構造函數實例化a1
const a1 = new Animal();
// 構造函數實例化a2
const a2 = new Animal();
// 調用實例的方法
a1.eat("food");
a2.eat("food");

從上面的代碼中,咱們能夠看到:spa

  1. 函數的prototype指向一個對象
  2. 函數實例化後的對象能夠獲取prototype指向對象的方法(和屬性)

那他們以前的關係是怎麼樣的呢?
圖片描述prototype

從圖中咱們能夠看到:code

  1. Animal的prototype指向一個對象
  2. Animal的實例經過__proto__關聯到Animal的prototype指向的對象

用官方術語說,就是:對象

  1. 函數的prototype所指向的對象就是該函數建立的實例的原型(即:a2和a2的原型是Animal.prototype)

那麼問題來了,什麼是原型呢?
在JavaScript中,每一個對象(null除外)在建立的時候都會與之關聯另一個對象,對象和原型之間經過__proto__進行關聯blog

原型的做用

在上面的代碼中,咱們能夠看到實例對象中並無eat方法,可是每一個實例對象均可以調用eat方法,那中間的過程是怎樣的呢?圖片

  1. 當咱們調用實例對象(a1和a2)的方法(eat)的時候,若是找到則直接調用實例對象的方法或者屬性;若是找不到,就會查找與之關聯的原型上是否有這個方法,若是這個原型沒有,就會繼續向上查找該原型的原型(原型的原型後面探討)

原型的原型

在上面咱們提到了若是在原型上找不到相應的屬性或者方法,就會在原型的原型上查找,那麼什麼是原型的原型呢?ip

  1. 首先在文章開頭咱們說每一個對象都有原型,而原型也是對象,因此原型也是有原型的(聽起來有點繞)
  2. 那以前代碼的Animal.prototype的原型指向哪裏呢(即Animal.prototype.__proto__)指向誰呢?這裏Animal.prototype是JavaScript內置構造函數Object生成的呢,那是否是應該指向Object.prototype呢?答案是是的。
  3. 那Object.prototype也是對象,它的原型呢?Object.prototype.__proto__指向哪一個對象呢?答案是:null;即:
Object.prototype.__proto__ === null // true
// 表示若是查找屬性的時候到Object.prototype時仍是沒有就中止,沒有了

最後畫張圖:
圖片描述原型鏈

原型鏈

注意到上圖中的藍色線條部分了嗎,這就是大名鼎鼎的原型鏈。

補充的知識

  1. constructor: 這個是原型中的自帶屬性,指向構造函數
  2. __proto__: 這個屬性實際上是瀏覽器實現的,不是標準的訪問原型的方式;ES5中規定的正式方法是:Object.getPrototypeOffang'fa
Object.getPrototypeOf(a1) === Animal.prototype // true

以上知識,最終的圖以下:
圖片描述

思考題:

  1. 在文章開頭咱們說過函數也是對象,既然是對象就有原型,那Animal的原型指向誰呢?
  2. Function.prototype === Function.__proto__ 是true嗎?
相關文章
相關標籤/搜索