simon

导航

[研究]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)。

posted on 2009-08-02 20:18  siemon  阅读(1967)  评论(6编辑  收藏  举报