jquery是面向对象的程序,面向对象就离不开方法和属性。

方法的简化

jQuery.fn=jQuery.prototype={

   jquery: 版本  

   constructor: 修正指向问题 

   init(): 初始化和参数管理

   selector:存储选择字符串

   length:this对象的长度

   toArray():转数组

   get(): 转原生集合

   pushStack():JQ对象的入栈

   each():遍历集合

   ready():DOM加载的接口

   slice():集合的截取

   first():集合的第一项

   last():集合的最后一项

   eq():集合的指定项

   map():返回新集合

   end():返回集合前一个状态

   push():(内部使用)

   sort():(内部使用)

   splice():(内部使用)

};

 这个属性可以通过jQuery对象来找到版本号。 先要引入jQuery库,alert($().jquery); 代码显示效果

jquery的2.0.3版本源码系列(3):96行-283行,给JQ对象,添加一些方法和属性

3.2 constructor属性的修正

第一点,原型对象的constructor属性是自动生成的。

首先来看constructor属性其实是原型对象的构造函数。

function Aaa(){

 }

//Aaa.prototype.constructor=Aaa;当一个函数创建完成,那么自动会在原型对象上生成constructor属性。
var al=new Aaa(); alert(al.constructor);

jquery的2.0.3版本源码系列(3):96行-283行,给JQ对象,添加一些方法和属性

可以看出来,弹出来的内容是这个对象对应的构造函数。其实当写完这个函数,constructor属性就生成了。

Aaa.prototype.constructor=Aaa;当一个函数创建完成,那么自动会在原型对象上生成constructor属性。那么看如下代码。
 function Aaa(){
        
 }
 alert(Aaa.prototype.constructor);

显示结果是

jquery的2.0.3版本源码系列(3):96行-283行,给JQ对象,添加一些方法和属性

第二,需要了解是constructor属性容易被修改。

既然constructor属性是自动生成的,可是为什么要做指定呢?原因在于constructor很容易被修改。

function Aaa(){

}
 
Aaa.prototype.constructor=Array;//指向constructor属性为数组Array。

alert(Aaa.prototype.constructor)

显示效果是

jquery的2.0.3版本源码系列(3):96行-283行,给JQ对象,添加一些方法和属性

那么来看两种不同的写法。

(1)通过点语法添加属性。constructor属性没有被修改。

function Aaa(){

}
 Aaa.prototype.name="hello";
 
 Aaa.prototype.age="29";
 
 var al=new Aaa();
 
alert(al.constructor);//返回的是Aaa函数,也就是constructor属性没有被修改。

(2)通过对象字面量覆盖的方式。由于constructor属性没有定义,所以原有的constructor属性就被修改了。

 function Aaa(){

 }
  Aaa.prototype={
            
         "name":"hello",
           
           "age":"29"
  };
   
 var al=new Aaa();
    
 alert(al.constructor);

jquery的2.0.3版本源码系列(3):96行-283行,给JQ对象,添加一些方法和属性

那么修正的方式是添加constructor属性。OK,对了。

 function Aaa(){

  }
   
Aaa.prototype={
            
       constructor:Aaa,
        
       "name":"hello",
        
       "age":"29"
};
        
var al=new Aaa();
       
 alert(al.constructor);

jquery的2.0.3版本源码系列(3):96行-283行,给JQ对象,添加一些方法和属性

3.3  init函数

我们知道,63行,对外提供接口只有$(或者说jquery),最终调用的是jQuery.fn.init。那么就是这里101行的init函数。

首先需要了解的是jQuery操作标签是把原生标签存放到this里。

如果是js,它的操作方式是通过原生的方式把li标签存起来。不过在jquery的面向对象的方式里并非如此,因为aLi是局部变量,那么就无法存取,必须通过this对象来共享。

<ul>
<li></li>
<li></li>
<li></li>
</ul>
var aLi=document.getElementsByTagName("li");
       
     for(var i=0;i<aLi.length;i++){
          
              aLi[i].style.background="red";

 }

jquery是通过this对象来存储原生标签的。

 this ={
          
          0:"li",
          
          1:"li",
           
          2:"li",
          
          length:"3"
}
       
for(var i=0;i<this.length;i++){
         
        this[i].style.background="red";
       
}

 关于这部分可以通过引入jQuery,来验证this对象里有存储原生标签。 console.log($("li")); 的打印结果如下。那么在for循环里就可以通过下标来访访问了。

jquery的2.0.3版本源码系列(3):96行-283行,给JQ对象,添加一些方法和属性 

当传入错误的内容时,105行

 // HANDLE: $(""), $(null), $(undefined), $(false)
            
       if ( !selector ) {  //当传入的是空字符串,null,undefined,false,那么直接返回
               
                    return this; 
            
        } 

传入字符串,110行

当传入HTML字符串时

 if ( typeof selector === "string" ) {

if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
                    //如果字符串的首个字符是小于符号,末位字符是大于符号,那么是HTML,会跳过正则检查。

match = [ null, selector, null ];
//比如,$("<li>")、$("<li></li><li>2</li>"),
//那么进入这个条件,match=[null,"<li>",null],match=[null,"<li>1</li><li>2</li>",null]。
                } else {
                    match = rquickExpr.exec( selector );
//如果传入的是$(".box")、$("div"),$("#div1 div.box"),match=null。
//如果传入的是$("#div1"),match=["#div1",null,"div1"]。
//如果传入的是$("<li>hello"),那么match=["<li>hello","<li>",null] }
// Match html or make sure no context is specified for #id
//匹配html或者确保没有上下文指定#id。


//如果match存在,并且match[1]存在或者context为空.那么进入这条语句的有:$("<li>")、$("#div1").

if ( match && (match[1] || !context) ) { // HANDLE: $(html) -> $(array) 处理html字符串:$("<li>")。
if ( match[1] ) { context = context instanceof jQuery ? context[0] : context; //instanceof判断传入的context是否是jQuery的实例。
 scripts is true for back-compat
jQuery.merge( this, jQuery.parseHTML( match[1], context && context.nodeType ? context.ownerDocument || context : document, true ) ); // HANDLE: $(html, props) if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { for ( match in context ) { // Properties of context are called as methods if possible if ( jQuery.isFunction( this[ match ] ) ) { this[ match ]( context[ match ] ); // ...and otherwise set as attributes } else { this.attr( match, context[ match ] ); } } } return this; // HANDLE: $(#id) 这里处理的是$("#div1")之类的。 } else { //XXXXXXX } //XXXXXX

context上下文,要么传入原生的document,要么传入$(document),最终 context instanceof jQuery ? context[0] : context 得到的是原生的document。$(document)对象打印出来的结果是,也就是 console.log($(document)); 。context事实上只能选择document。它跟iframe有关,其实没有太大用处。

jquery的2.0.3版本源码系列(3):96行-283行,给JQ对象,添加一些方法和属性

parseHTML是用来做什么的?

首先,parseHTML会把传入的HTML字符串转换为数组。

 <script src="jquery-2.0.3.min.js"></script>
    
<script>
       
        var str="<li>1</li><li>2</li><li>3</li>";
        
        var arr=jQuery.parseHTML(str)
       
        console.log(arr);

</script>

打印的结果是一个数组。

jquery的2.0.3版本源码系列(3):96行-283行,给JQ对象,添加一些方法和属性

再次,这些原生的标签,可以被追加到某个标签上。

<script src="jquery-2.0.3.min.js"></script>
    
<script>
       
       var str="<li>1</li><li>2</li><li>3</li>";
       
       var arr=jQuery.parseHTML(str)
       
        $.each(arr,function(i){
           
              $("ul").append(arr[i]);

       })
    
</script>

显示效果如下

jquery的2.0.3版本源码系列(3):96行-283行,给JQ对象,添加一些方法和属性

最后,第三个参数如果设置为true,是为了让script标签能够执行js代码。默认false禁止js代码执行。

<script src="jquery-2.0.3.min.js"></script>
    
<script>
       
       var str="<li>1</li><li>2</li><li>3</li><script>alert('4')<\/script>";
       
       var arr=jQuery.parseHTML(str,document,true)
       
       $.each(arr,function(i){
          
               $("ul").append(arr[i]);
       
       })
</script>

jquery的2.0.3版本源码系列(3):96行-283行,给JQ对象,添加一些方法和属性

jQuery.merge函数的功能是合并。可以合并数组,也可以合并json。

 <script src="jquery-2.0.3.min.js"></script>
    
<script>
       
      var arr={
           
           0:"a",
          
           1:"b",
           
           length:2
       }
       
      var arr2=["c","d"];
      
       console.log($.merge(arr,arr2));
    
</script>

合并为一个对象,对象的打印结果是

jquery的2.0.3版本源码系列(3):96行-283行,给JQ对象,添加一些方法和属性

那么最终就能够合并到我们想要的this数组的形式。

例如

<script src="jquery-2.0.3.min.js"></script>
    
<script>
        
       console.log($("<li>0</li><li>1</li><li>2</li>"));
    
</script>

jquery的2.0.3版本源码系列(3):96行-283行,给JQ对象,添加一些方法和属性

if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
                            
       for ( match in context ) {
                                
      // Properties of context are called as methods if possible
                               
       if ( jQuery.isFunction( this[ match ] ) ) {
                                   
                this[ match ]( context[ match ] );

                                   
       // ...and otherwise set as attributes
                                
       } else {
                                    
              this.attr( match, context[ match ] );
                               
        }
                            
      }
                       
 }

这是这部分的最后一段儿代码。首先,标签检测是不是单标签,context是不是对象字面量。单标签只有两种类型,要么是类似"<li>",要么是类似"<li></li>"

<script src="jquery-2.0.3.min.js"></script>
    
<script>
        
        $("<li>",{title:"hello",html:"abcd"}).appendTo("ul");

</script>

显示效果,如下。首先li标签的内容是abcd,然后由于添加了title,所以鼠标移上去会有"hello"的提示。

jquery的2.0.3版本源码系列(3):96行-283行,给JQ对象,添加一些方法和属性

for(match in context)循环要做什么呢? 那么添加一些伪代码,就能够清楚他们都干了什么,context就是第二个参数,this就是$()通过传入参数获得的jQuery对象。

 

$("<li>",{title:"hello",html:"abcd"}).appendTo("ul");
       
 var context={title:"hello",html:"abcd"};
      
 var thisObject=$("<li>",{title:"hello",html:"abcd"});
       
      for ( match in context ) {
            
            // Properties of context are called as methods if possible
            
             if ( jQuery.isFunction( thisObject[ match ] ) ) {
               
                    console.log("if语句"+match);
              
                   thisObject[ match ]( context[ match ] );

               
             // ...and otherwise set as attributes
 
 } else {
                
               console.log("else语句"+match);
               
               //this.attr( match, context[ match ] );
           
           }
 
 }

 

那么传入的 {title:"hello",html:"abcd"} title属性进入else循环,根据142行的代码,使用this.attr添加到元素的属性上。html属性因为是jQuery的函数,也就是html(),那么进行函数调用,就像$().html()一样。

(3)传入id值的处理。

对应的代码是150行到164行,如下代码

} else {
                        
                       elem = document.getElementById( match[2] );

                        // Check parentNode to catch when Blackberry 4.6 returns
                        // nodes that are no longer in the document #6963
                       
                        if ( elem && elem.parentNode ) {
                           
                       // Inject the element directly into the jQuery object
                           
                            this.length = 1;
                            
                            this[0] = elem;
                      
                        }

                        this.context = document;
                       
                        this.selector = selector;
                       
                       return this;
                   
 }

首先要弄清楚match数组是什么。如果传入的是"#div1",match数组会长成 match=["#div1",null,"div1"]; 那么对于html代码, <div id="div1">div1</div> 。

<script src="jquery-2.0.3.min.js"></script>
    
<script>
        
       match=["#div1",null,"div1"];
       
        elem = document.getElementById( match[2] );
        
        //<div >div1</div>

</script>

 

而下面的代码155行到159行,对于黑莓4.6浏览器的兼容性代码,即使html并没有这个元素,竟然还能够找到。就目前国内的情况黑莓用户很少,可以不用去管它。

if ( elem && elem.parentNode ) {
                            
       // Inject the element directly into the jQuery object
                           
                 this.length = 1;
                            
                 this[0] = elem;
}

  this.context = document; 重置上下文。  this.selector = selector; 则是把selector选择器赋给this对象的seletor属性。

(4)传入复杂标签的处理,比如$("ul li.box"),$(".box")、$("#div1 div.box")。当执行上下文不存在时,走的是这一条路径,都是通过find方法来查找,具体说起来是sizzle引擎的查找。

 } else if ( !context || context.jquery ) {
                  
           return ( context || rootjQuery ).find( selector );

                    
                   // HANDLE: $(expr, context)
                  
                   // (which is just equivalent to: $(context).find(expr)

  } else {
                   
          return this.constructor( context ).find( selector );
               
 }

如果context不存在,那么返回的是通过rootjQuery也就是$(document)来寻找选择器,也就是复杂标签,相当于 $(document).find("ul li.box"); 。如果存在上下文context, $("ul li.box",document); 对应的是else if语句。

 $("ul li.box",$(document)); 对应的是else语句。最终执行的都是 $(document).find("ul li.box"); 。

当传入的是节点,177行

 } else if ( selector.nodeType ) {
                this.context = this[0] = selector;
                this.length = 1;
                return this;
                // HANDLE: $(function)
                // Shortcut for document ready
}
当传入的是节点的源代码

相关文章: