- 每個函數(箭頭函數除外)都有prototype屬性,該屬性指向原型。
- 每個對象(null除外)都有__proto__屬性,指向了創建了該對象的構造函數的原型。(注:函數也是對象)
- 對象可以通過__proto__來尋找不屬於該對象的屬性,__proto__將對象連接起來組成了原型鏈。
理解原型和原型鏈,下面這張圖很重要:
根據上面這張圖,能夠得到如下等式:
// 一、對象的__proto__指向其構造函數的原型
f1.__proto__ === Foo.prototype
// 二、對象的__proto__指向其構造函數的原型
f2.__proto__ === Foo.prototype
// 三、Foo.prototype本質是一個對象,其構造函數是Object
Foo.prototype.__proto__ === Object.prototype
// 四、Foo是普通函數(函數也是對象,所以有__proto__屬性),其構造函數是Function
Foo.__proto__ === Function.prototype
// 五、這一條比較特殊,也很合理。Funcion既是對象又是函數(而且不是普通函數,是所有普通函數的構造函數)。
// 因為是對象,所以有__proto__屬性,指向其構造函數(自己)的原型。
Function.__proto__ === Function.prototype
// 六、同三
Function.prototype.__proto__ === Object.prototype
// 七、Object是所有對象的構造函數,是一個函數,函數的構造函數是Function
Object.__proto__ === Function.prototype
// 八、所有對象順着原型鏈最終都會找到Object.prototype,而Object.prototype.__proto__ = null即是原型鏈的終點
Object.prototype.__proto__ === null
上面的等式都清楚了之後,下面這些等式應該也能夠推導出來了:
Object.__proto__.__proto__ === Object.prototype
Object.__proto__.__proto__.__proto__ === null
Function.__proto__.__proto__ === Object.prototype
Function.__proto__.__proto__.__proto__ === null
其實在做推導時,抓住幾個關鍵,就不容易被繞暈掉了:
- 函數也是對象
- 看到x.__proto__時,就要把x看成對象(哪怕它是個函數),繼而想到“對象的__proto__指向其構造函數的原型”
- 看到x.prototype時,就要想到x肯定是個函數,x.prototype作為一個整體表示函數x的原型,其實就是個對象