面向對象語言(Object-Oriented) 都有類的概念,通常用 class 關鍵字來定義。在最新的 ES6 標準里,也加入了類的使用,這意味著,js 也能像其它 OO 語言那樣很方便地實現繼承了。但是,js 的 class 其實只是個語法糖,它依然是通過原型鏈來實現繼承的。
在理解原型鏈之前,首先要理解一句話,構造函數、原型和實例三者的關系:每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。
理解 prototype、proto 和 constructor
上面這句話對應著幾個屬性:prototype ,__proto__ 和 constructor 。
每個函數在被創(chuàng)建的時候,都會獲得一個 prototype 屬性,這個 prototype 屬性會包含一個指針,叫做 constrcuctor ,這個 constructor 的值是構造函數的名稱。所以對應了上面那句話:每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針 。我們通過 Chrome 控制臺來驗證一下:

可以看到,我們定義了一個函數,函數名為 f ,f 的原型 prototype 里的 constructor 最終是等于它的構造函數名稱的,那么這個 constructor 屬性究竟是用來干嘛的?在查閱了網上相關資料后,我發(fā)現它是 JavaScript 語言設計的歷史遺留物,它的值是可以手動變更的,但我們習慣于讓它的值指向構造函數。
看上面的圖仔細看會發(fā)現函數的 prototype 里還有一個 __proto__ 屬性。這個屬性是每個對象都會有的隱式屬性。那在 JS 這門語言里,萬物皆對象。你在 console 里輸入 typeof f 會輸出 function ,但 function 也是對象。不信你在輸入 Function instanceof Object 看看結果。這個 __proto__ 對于實現繼承有非常重要的作用,它始終指向對象的構造函數的原型。 這個屬性對于我們理清兩個對象之間的關系有很大的作用。
當我們 new 一個對象的時候,實際上就是生成了該對象的實例,這個實例對象會獲得一個 __proto__ 屬性,鏈接到它的構造函數原型。這樣下來就好理解了,前面我們定義的 function f(){} 實際上 function 只是一個語法糖,為了好看而已,它的內部是做了一個 new Function() 的實現,Function 可以理解為所有函數的老大,我們平常使用關鍵字定義的函數內部都是去 new Function 實現的。
那既然函數 f 是 Function 的實例,那它肯定會獲得一個 __proto__ 屬性,這個屬性是指向它的構造函數 Function 的原型 prototype 的。眼見為實,我們來驗證下:

對于開頭提到的構造函數、原型和實例三者的關系,我想你應該有了概念了。為加深理解,我把它畫成了圖,如下:

原型鏈
在理解了原型之后,我們來看下原型鏈。讓一個原型去繼承另一個原型的屬性和方法,就組成了原型鏈。就像前面的 finstance 是函數 f 的實例,f 又是 Function 的實例,... 就這樣一層一層下來,就組成了原型鏈。我們來看一段代碼:
function Dad(){
this.name = 'xiaoming';
}
Dad.prototype.getName = function(){
return this.name;
}
function Son(){
this.age = 18;
}
Son.prototype = new Dad();
var baby = new Son();
console.log(baby.getName()); // xiaoming
上面這個就是繼承的一種最簡單的實現方式了,我們來看下它的原型鏈,首先 Dad 是父類,它有自己的屬性 name,它的原型里定義了一個 getName 的方法。接著有一個子類 Son 繼承 Dad ,它也有自己的屬性 age,我們通過設置 Son.prototype = new Dad(); 來實現原型繼承,這樣子類 Son 可以訪問到父類 Dad 的屬性和方法,所以子類的實例 baby 可以獲取到 name 屬性和 getName() 方法。
我們通過一張圖來看下它的原型鏈:

總結
__proto__ 屬性通過將對象和原型之間聯系起來來組成原型鏈;理解原型鏈,先要理解 prototype 、constructor 和 proto 這幾個概念,理清構造函數、原型和實例三者的關系,結合實際效果來驗證。JS 不像其它 OO 語言那樣,它是通過原型鏈來實現繼承的。這部分內容比較晦澀比較繞,耐心地多看多實踐,不懂的網上查閱資料,也許就有所理解。