首页 > 代码库 > Javascript 原型继承(续)—从函数到构造器的角色转换

Javascript 原型继承(续)—从函数到构造器的角色转换

      对于每一个声明的函数,里边都会带有一个prototype成员,prototype会指向一个对象,现在我们来聚焦prototype指向的这个对象,首先我们会认为,这个对象是一个该函数对应的一个实例对象,因为我们在new一个对象的时候,通常都会继承该原型prototype对象的属性和方法。比如:

 1 <html>
 2         <head>
 3         <meta  http-equiv="content-type" charset="utf-8"/>
 4         <script type="text/javascript">
 5          function person()
 6          {
 7               this.name = "istone";
 8               this.age = 10;
 9               this.address = "shenzhen";
10          }
11          var tt = new person();
12          alert("name : "+tt.name+"\nage : "+tt.age+"\naddress : " +tt.address);
13         </script>
14         </head>
15         <body> 
16         </body>
17 </html>

由以上代码我们发现由于原型对象继承机制的存在,对象tt在创建后便拥有的原型对象的相关属性,在这里是否我们可以认为原型对象是一个拥有某些属性和方法的一个对象,若是这样,我们每声明一个函数,其prototype成员对象一开始便拥有了一些属性和方法。显然这是不经济的。所以我们可以这样认为,当我们在声明一个函数时,其prototype对象是一个空的对象。但为什么我们在用new操作符创建一个新对象后(比如tt)便已经拥有了一些属性和方法呢,这不是明显与空对象的概念相矛盾麽?下面我们来解决这个问题,先看如下代码:

 1 var _proto = null;
 2 function GetPrototype()
 3 {
 4    if(!_proto)
 5 {
 6    _proto = new Object();
 7     _proto.constructor = this;//构造函数
 8 }
 9 return _proto;
10 }

以上代码是推断出来的prototype的可能实现逻辑,函数原型在一开始便是一个内置的Object构造器的实例,并且constructor属性被赋值为当前函数,此时的函数就充当了构造器的作用了。当函数的prototype有意义后,就从普通函数摇身变成了构造器。这时当用户用new产生实例,只要该实例的原型链接向这个prototype属性就可以了。

附:Jquery对象的构建分析

step 1:一般我们都建对象的方式就是采用new运算符来实现。

 1  function iQuery()
 2  {
 3                               
 4      this.name = "istone";
 5      this.age = function(){
 6      alert("I‘m 10 years old!");
 7      };
 8 }
 9 var IStone = new iQuery();
10 IStone.age();

step 2:显然Jquery不是这么玩的,它并没有想step 1一样用new来构建对象,而是直接调用函数。比如:

$().ready(obj);

$().isFunction(obj);

要达到这样的效果我们必须在调用’$()’的时候得到一个实例对象。

function iQuery()

{                   

    return new iQuery();

}

iQuery.prototype.name= "istone";

iQuery.prototype.age = function()

{

     alert("I‘m 10 years old!");

};

很明显这样会有一个问题,就是死循环了。

step 3:为了解决这个问题,Jquery将实例对象的获得转移到了prototype中。

 1 function iQuery()
 2 {
 3     return iQuery.prototype.init();
 4 }
 5 iQuery.prototype={
 6 init:function()
 7 {
 8     return this;
 9 },
10 name: "istone",
11 age : function()
12 {
13     alert("I‘m 10 years old!");
14 
15 }
16 }

在这里返回this关键字是极其关键的一步,此时的this上下文为init.prototype,代表着init函数的原型。因此这样还是达不到效果。但Jquery通过巧妙的将init的原型替换为Jquery的原型,此时瞬间就解决了这个问题。此时this上下文就转为了Jquery的原型了。

iQuery.prototype.init.prototype = iQuery.prototype;

PS:下面是JQuery对象构建的部分源码,通过上面的分析,咱们就能清楚地了解这一构建过程。

 1 jQuery = function( selector, context ) {
 2         // The jQuery object is actually just the init constructor ‘enhanced‘
 3         return new jQuery.fn.init( selector, context, rootjQuery );
 4     },
 5 
 6 jQuery.fn = jQuery.prototype = {
 7     init: function( selector, context, rootjQuery ) {
 8     
 9             return this;
10 }
11 }
12 jQuery.fn.init.prototype = jQuery.fn;