建構函式、原型及原型鏈

王振宇發表於2019-03-19

什麼是建構函式?

建構函式本身就是一個函式,與普通函式沒有任何區別,不過為了規範一般將其首字母大寫。建構函式和普通函式的區別在於,建構函式用於使用new操作符生成例項,普通函式用來呼叫以實現某種功能。

什麼是原型?

每個函式都有一個prototype屬性,prototype屬性中的constructor屬性又指向函式自身。

什麼是原型鏈?

引用高程3的描述:每個建構函式都有一個原型物件,原型物件都包含一個指向建構函式的指標,而例項都包含一個指向原型 物件的內部指標。那麼,假如我們讓原型物件等於另一個型別的例項,結果會怎麼樣呢?顯然,此時的 原型物件將包含一個指向另一個原型的指標,相應地,另一個原型中也包含著一個指向另一個建構函式 的指標。假如另一個原型又是另一個型別的例項,那麼上述關係依然成立,如此層層遞進,就構成了實 例與原型的鏈條。這就是所謂原型鏈的基本概念。

如果你還沒理解建構函式和原型的關係,看完對於上面這段話,很可能更加暈了,所以下面我將用我的理解來描述建構函式和例項之間的關係,以及原型鏈到底是什麼。

function Person(name){
  this.name = name;
};
let xm = new Person('小明');
xm.__proto__ === Person.prototype  // true 
xm.__proto__.constructor === Person  // true
Person.prototype.constructor === Person  // true複製程式碼

Person為建構函式,xm是通過new Person()得到的例項,其對應關係如下圖:

建構函式、原型及原型鏈

而如果我們這裡的Person.prototype同時又是另一個foo建構函式的例項呢?Person.prototype可以從foo.prototype繼承屬性和方法,xm又可以從Person.prototype繼承屬性和方法,由此得出以下結論:

每個物件都擁有一個原型物件,通過__proto__指標指向上一個原型 ,並從中繼承方法和屬性,同時原型物件也可能擁有原型,這樣一層一層查詢,最後指向Object.prototype,接著Object.prototype.__proto__ = null,物件之間的這種關係就是原型鏈。

那麼如上程式碼的原型鏈關係圖如下:

 建構函式、原型及原型鏈

那如果加上Function物件又是什麼樣的呢?上圖:

建構函式、原型及原型鏈

上圖有一個讓人疑惑的點就是為什麼Function.__proto__ === Function.prototype?

我比較認同的一種觀點是:Function作為一個內建物件,是執行前就存在的東西,所以不會存在說Function自己建立自己,而同Function一起被建立的還有Function.prototype和Object.prototype,並通過__proto__將兩者聯絡起來,而為了和其他物件保持一致性,將Function.__proto__指向Function.prototype。

總結:

Object是所有物件的祖先,所有物件都可以通過__proto__找到Ojbect.prototype;

Function是所有函式的祖先,所有函式都可以通過__proto__找到Function.prototype;

每一個例項通過__proto__指向建構函式的原型,而建構函式的原型又通過__proto__指向建構函式的原型的原型,如此一層一層連結的關係,就是原型鏈。

如果有錯誤或者不嚴謹的地方,請給予指正,十分感謝!

相關文章