[研究]Javascript中Function和Object之间的关系
之前在网上看到一个问题:
var n = new Number(1)
n.prototype -> undefined
为什么n.prototype为undefined? 碰到这个问题我一时也摸不着头脑。因为我们知道new Function().prototype为object.由此问题引发我对Function和Object研究的兴趣。
上图是能够通过代码来验证的Function和Object之间的关系。
蓝色线为类的constructor的实例
橙色线为类的实例
绿色线为类的prototype的实例
黑色线为类的constructor的prototype的实例
下面来证明:
1.Function instanceof Object -> true
2.Object instanceof Function -> true
此时橙色关系成立。由此还可得出,Function和Object各为自身的实例。
3.Function.constructor === Function -> true
4.Object.constructor === Function -> true
由此蓝色关系成立,并得知Object是通过Function进行构造的,而Function则由自己构造自己。
5.Function.prototype instanceof Object -> true
6.Object.prototype instanceof Object -> false
绿色关系成立,因此也就是说,Function的原型对象是Object的实例,可依据3、4、5的关系,得知黑色关系:
7.Function.constructor.prototype instanceof Object -> true
8.Object.constructor.prototype instanceof Object -> true
无论我们创建String\Boolean\Object\Number哪个实例,当你妄图使用new Object().prototype的时候都会得到undefined,说明此实例中并不包含此属性,但实际上是隐含一个内部的[[Prototype]]的,它的值就是此类型的原型对象,比如:Object.prototype,不过我们没法使用它。但是仍可以通过另一种途径获得:
var s = new String();
s.constructor.prototype -> object
此时得到的就是String的原型对象。
s.constructor.prototype.hello = 'hello';
new String().hello -> 'hello';
这样就可以通过实例去扩展其原型对象了。效果等同于String.prototype.hello = 'hello'。
由上面的证明得知,可以通过任意一个实例去访问到Function.prototype。
s.constructor.constructor.prototype.newproperty = 'newproperty';
new Function().newproperty -> 'newproperty';
这样以来你创建的所有Function实例都将拥有这个newproperty了。但是却永远不可能通过实例去得到Object.prototype(Object类的实例可以通过上述方法得到Object.prototype,比如:new Object().constructor.prototype,但非Object类的实例都无法得到Object.prototype),因为所有实例都不直接拥有prototype的值为Object.prototype的属性,你如果试图使用constructor去获得Object.prototype,将陷入Function.constructor的循环之中,因为Function的constructor是他自己,这样就保护了Object.prototype,因为所有对象都依它为原型,如果从哪里都可以对它进行访问的话,程序可能会陷入极度混乱之中。
其实,使用prototype的目的就是为了实现类(Class)的属性共享与继承。我们在prototype对象上进行属性的扩展,其实例和子类型都会拥有这一属性。而对于非同一般的new Function().prototype而言,此处的prototype也不是Object.prototype。规范上有一句可以解释:
每一个function(Function Object)都会自动创建一个prototype属性,原因是此function(Function Object)可能会被当作constructor。
也就是说,当你使用new关键字时function就被当作constructor。
使用new Function().prototype.constructor可以得到一个匿名函数。这个匿名函数实际上就是通过new Function()创建的。new Function()会生成function anonymous(){}。如果你使用这种形式:new new Function();那么将得到anonymous类的一个实例。再来看一段代码:
function Foo(){}.prototype.constructor -> function Foo(){}
也就是说,function Foo(){}的prototype对象又有一个指向其本身的constructor属性。更进一步。
function Foo(){};
Foo.prototype.constructor -> function Foo(){}
new Foo().constructor === Foo.prototype.constructor -> true
new Foo() instanceof Foo.prototype.constructor -> true
Foo.prototype instanceof Foo -> false
因此得知,Foo.prototype的对象并非由Foo进行构造(并非由其本身构造,包括Object.prototype,见证明6),而是由更高级别的构造机制进行构造的(Object.prototype应该存在一种最高级的构造机制,如果Object.prototype由其本身进行构造,原型链就会陷入循环)。所有类的实例确有其本身进行构造,由此你才能获得new Foo() instanceof Foo -> true 的结果。而所有类(Class)则须通过Function构造,换句话说,也就是所有类都是Function的实例,而Function和Object又互为对方实例,因此所有类也是Object的实例。而所有类的prototype对象也都是Object的实例(如:Foo.prototype instanceof Object -> true,除Object.prototype外),所以所有类的实例也同时为Object的实例(这种描述可能不够准确,因为Object.prototype不是Object的实例。另,在Object.prototype对象内部的[[prototype]]值为null,内部的[[Class]]值为Object)。