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来构建基类。