JS中除null和undefined幾乎都存在可讀屬性prototype和constructor,且默認情況下prototype屬性中還包含一個指向超類constructor屬性的對象。
JS中所有的對象有一個prototype屬性和constructor,默認下,prototype指向Obejct{}或functionName{}或者繼承的超類。這里要注意的是null和undefined沒有prototype屬性或者至少是不可讀的。
這里我想先說明一個問題。JS中的類沒有如PHP、Java或者C++中的private等可見性,雖然private等本身被作為關鍵字保留了,但并沒有實際的應用。另外JS中對象方法(或類方法)的定義有兩種方式:
function A(){}
function B(){}
A.a1=function(){....}
A.prototype.a2=function(){.....}
兩者的區別表現在繼承上,如果B繼承A時只用B.prototype=A,那么B實際上只得到了a1方法;如果B繼承時只用B.prototype=A.prototype,那么B實際上只得到了a2方法。且通過后者的方式instanceof判斷 B instanceof A時會返回True。實際使用時需要根據情況的需要使用。
因為通過prototype屬性,我們可以方面的構造或繼承類,所以在實際使用中必然會產生OOP的經典問題類型檢測(或is_like問題)。雖然JS中的typeof可以判斷出對象的類型,但對這個需求沒有幫助。instanceof的檢測,左邊是要檢測的對象,右邊是要判斷的prototype屬性,它可以判斷出類的繼承關系。比如
function A(){}
function B(){}
function C(){}
function O(){}
A.prototype = O.prototype;
B.prototype = A.prototype;
C.prototype = B.prototype;
那么instanceof對于 new A() instanceof O、new B() instanceof O、new C() instanceof B都會給出Ture的返回。但問題在于JS默認的所有對象的prototype都最終指向Object.prototype,所以他對我們的幫助極其有限。這時constructor可以幫助我們。
constructor屬性在JS中同prototype一樣是普遍存在,默認下,constructor指向內置類型方法或者function Function(){[native code]} 或 function Object(){[native code]}。同prototype一樣,null和undefined的constructor至少是不可讀的。從默認的指向來看我們就能知道typeof實際上是對于自身constructor屬性的驗證。
JS中prototype中還存在一個不可枚舉的屬性constructor,我們就是靠利用這點來正確的判斷對象的實際構造者的。如
function A(){}
function B(){}
function C(){}
A.prototype={constructor:A,somefunc:....}
B.prototype=A.prototype;
C.prototype=B.prototype;
這時雖然instanceof的運算依然是給出Ture,但是當我們比較C.prototype.constructor==B時會得到False,而C.prototype.constructor==A卻是Ture。這樣我們就能夠確認C究竟是B還是A。當然constructor除了也可以是一個獨立的對象,但即使執行了new操作后也不能使用該對象中定義的方法。
綜上,我們完全可以利用prototype.constructor來構建基類。