1、首先建構函式為中心
function Person() { }
var p = new Person();
console.log('Person::', p)
console.log(p.constructor === Person)
列印如下:
可以看出建構函式透過new得到例項,例項可以透過【constructor】得到建構函式。
訪問原型的方式:
① 顯示原型 建構函式透過prototype訪問原型
② 隱私原型(向上) 例項透過__proto__訪問原型
也就是 p.__proto === Person.prototype
根據上述畫出他們的關係圖如下:
2、以Object為中心
物件的一些建立方式:
var obj1 = {};
var obj2 = new Object();
這裡我們用new的方式建立一個物件:
var obj = new Object();
列印物件例項的原型(obj.__proto__
);)如下圖:
有上圖可以看出例項obj的__proto__已經到頂,如果在__proto__去找,就找到了null,也就是obj.__proto__
.__proto__
=== null。
接下來我們在拿上邊的Person舉例
function Person(){};
var p1 = new Person();
console.log(p1.__proto__.__proto__.__proto__ === null ) // true
透過Person的例項去找原型,透過三次__proto__才找到null,p1為什麼要比obj多一層吶?其實主要就是建構函式中存在 Person 比Object多一層prototype作為自定義屬性原型使用。
下邊在畫一下已Object為中心的關係圖如下:
將上邊兩個關係圖連起來:
3、下邊已Function為中心:
首先我們定義一個函式var fn = new Function();
然後列印這個fn,結果如下圖:
有印表機結果,可以看出例項fn 也可以透過兩次__proto__找到object原型,到這裡有個疑問就是例項fn 一次__proto__是什麼?
列印一下fn.__proto__結果如下(這裡注意下Function.prototype也是這個結果,也就是fn.__proto__
===Function.prototype的結果是true ):
可以看出是[native code], 而native code 是底層的一個函式,其實負責函式的呼叫,底層程式碼我們是看不到的,在這裡我麼也可以看出函式也需要具備物件的能力。
和上邊的已建構函式和Object為中心的關係連起來如下圖:
這裡再重點說下Function:
首先思考一個問題,__prroto__其實在任何的物件上都可以用,那麼函式其實也是一個物件,那麼Function.__proto__是什麼吶?__proto__是用來找原型的,那麼Function.__proto__就是再找函式的原型,我們列印Function.proto__可以看下,也是一個[native code],所以到這裡我們可以知道Function. proto __ === Function.prototype的結果也是true,也就是他們都會找到底層的一個函式,這裡我們可以得出一個結論:無論是Function.proto 找原型還是Function.prototype的方式找原型都是一樣的結果,如下圖:
總結:由於Function既是物件也是函式,所以自身和建立的例項,都指向function原型。
補充:基本型別的包裝型別也是有原型的如下圖: