基于jquery-2.0.3的源码学习

// 2.给JQ对象添加一些方法和属性
            /*jQuery.fn = jQuery.prototype = {  //添加实例属性和方法 prototype 属性使您有能力向对象添加属性和方法。
            
            jquery : 版本
            
            constructor : 修正指向问题
            
            init() : 初始化和参数管理
            
            selector : 存储选择字符串
            
            length : this对象的长度
            
            toArray() :  转数组
            
            get() :  转原生集合
            
            pushStack() :  JQ对象的入栈
            
            each() :  遍历集合
            
            ready() :  DOM加载的接口
            
            slice() :  集合的截取
            
            first() :  集合的第一项
            
            last() :   集合的最后一项
            
            eq() :   集合的指定项
            
            map() :   返回新集合
            
            end() :   返回集合前一个状态
            
            push() :    (内部使用)
            
            sort() :    (内部使用)
            
            splice() :  (内部使用)
            
        };*/
 jQuery.fn = jQuery.prototype ={   //prototype 属性使您有能力向对象添加属性和方法。
     jquery:core_version,//jq的版本号
     constructor:jQuery,//修正指向问题 因为是简写的所以要写此代码指定一下指向
     init:function(selector,context,rootjQuery){    //初始化和参数管理 selector代表选择元素
      var match, elem;
      // HANDLE: $(""), $(null), $(undefined), $(false)
      if(!selector){  //如果选择的不是正确的元素直接返回
        return this;
      }
      // Handle HTML strings选择的是字符串如$('#div1') $('.box') $('div')  $('#div1 div.box') $('<li>')  $('<li>1</li><li>2</li>')
      if(typeof selector ==="string"){//处理选择的元素是字符串类型 charAt() 方法可返回指定位置的字符。
           if(selector.charAt(0)==="<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >=3){  //找标签
              //如果是单标签$('<li>')则match=[null,'<li>',null]
              //如果是多标签如$('<li>1</li><li>2</li>')则match=[null,'<li>1</li><li>2</li>'] 
            match = [null,selector,null];   
           }else{
             // 把selector进行匹配,如果匹配成功,
             //match数组第一个元素是selector,
             //第二个元素是HTML或者是undefined,
             //第三个元素是ID或者是undefined。
             match = rquickExpr.exec( selector );
           }
           // Match html or make sure no context is specified for #id
            // 判断字符串是否是一个单独的标签
        // 如果match[1]不是undefined,即参数selector是HTML代码,或者match[2]不是undefined,即参数selector是#id,
        //并且未传入参数context。完整版的判断如下“if (match && (match[1] || match[2] && !context)) {}”,
        //为什么省略了对match[2]的判断?因为如果match不是null且match[1]是undefined,
        //那么此时match[2]必然不是undefined,所以对match[2]的判断可以省略。
           if(match && (match[1] || !context) ){ //如果是标签或id进入if
            // HANDLE: $(html) -> $(array)
            //判断字符串是html
             if(match[1]){
               //instanceof运算符用来判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上
                //修正context:“context = context instanceof jQuery ? context[0] : context;”。
                //先判断第二个参数的类型在将context赋值成原生的节点。例如输入的是:$('li',document)或$('li',$(document))。   
               context = context instanceof jQuery ? context[0]:context;
               //jQuery.parseHTML()用于将HTML字符串解析为对应的DOM节点数组。有三个参数:htmlString,context,keepScripts。
               //HTMLString,string类型,需要解析并转为DOM节点数组的字符串。
               //context,element类型。指定在那个document中创建元素。默认为当前文档的document。
               //keepscript,boolean类型,指定传入的字符串中是否包含脚本,默认为false。
               //$.merge() 函数用于合并两个数组内容到第一个数组。
              // 我们传入了三个参数:"match[ 1 ],
              //context && context.nodeType ? context.ownerDocument || context : document,true"。
              //如果context与context的节点存在,使用context或context的owner document,否则用默认参数domcument。
                // jQuery.merge()用于合并两个数组内容到第一个数组。注意这时传入的this是个json对象而不是数组,通过这种方式也能进行合并并返回jQuery想要的json格式。
               jQuery.merge(this,jQuery.parseHTML(
                   match[1],
                   context && context.nodeType ? context.ownerDocument || context : document,
                   true
               )); 
                // 解析$(HTML, props)格式
                // 如果正则rsingleTag验证"match[1]"是否是一个单独的标签,且context是一个纯粹的对象条件成立。
                //循环这个json对象,并判断json里的属性是否是jq自带的方法,如果是,则直接调用方法,否则,用jq的attr方法为这个标签加一个“match”属性。
               if(rsingleTag.test(match[1])&& jQuery.isPlainObject( context )){
                  for(match in context){
                      if(jQuery.isFunction( this[ match ] )){ //$.isFunction()函数用于判断指定参数是否是一个函数。
                        this[ match ]( context[ match ] );
                      }else{
                        this.attr( match, context[ match ] );//否则,用jq的attr方法为这个标签加一个“match”属性。
                      }
                  }
               } 
               //返回当前对象
               return this;   
             }
            //判断字符串是ID且未指定参数
           else{
              //match数组第一个元素是selector,
              //第二个元素是HTML或者是undefined,
              //第三个元素是ID或者是undefined。
              //使用getElementById()方法查找含有Id属性的DOM元素
              elem = document.getElementById(match[2]);
              //如果DOM元素存在,设置第一个元素,属性length,并返回当前对象。
              if(elem && elem.parentNode){
                this.length =1;
                this[0] = elem;
              }
              this.context = document;
              this.selector = selector;
              return this; 
           }
        }// 判断字符串是选择器表达式
        else if(!context || context.jquery ){
          // 如果没有指定上下文,则执行root.find(selector);如果指定了上下文,且上下文是jQuery对象,则执行context.find(selector);
          return ( context || rootjQuery ).find( selector );
        }else{
           // 如果制定了上下文,但上下文不是jQuery对象,则执行
           //find() 方法获得当前元素集合中每个元素的后代,通过选择器、jQuery 对象或元素来筛选。
          return this.constructor( context ).find( selector );
        }
    }else if(selector.nodeType){//选择节点的方式
      //  如果参数selector含有属性nodeType,则认为selector是DOM元素,
      //设置第一个元素指向该DOM元素、属性length为1,
      //然后返回包含了改DOM元素引用的jQuery对象。:
      //nodeType声明了文档树中节点的类型,
      //例如,element节点的该属性值是1,text节点是3,comment是9,document是9,documentfragment节点是11。
    // 参数selector是节点,设置第一个元素、属性length,并返回当前对象。
         this.context = this[0] = selector;
         this.length = 1;
         return this;
    }else if(jQuery.isFunction(selector)){ // 参数selector是函数
      return rootjQuery.ready(selector);
    }
    if(selector.selector !== undefined){ //selector是jquery对象
      this.selector = selector.selector;
			this.context = selector.context;
    }
    return jQuery.makeArray( selector, this ); //$.makeArray() 函数用于将一个类似数组的对象转换为真正的数组对象。
 },
 selector:"",//存储选择字符串
 length:0,//this对象的长度length表示当前jQuery对象中元素的个数。
 toArray:function(){ //转数组方法将当前jQuery对象转换为真正的数组,转换后的数组包含了所有的元素
    // 连同slice()一起声明的还有concat()、push()、indexOf()、toString()、hasOwn()、fnToSting()、objectFunctionSting()这些方法。
    //这里通过声明这些核心方法的引用,
    //使的在jQuery代码中可以借用这些核心方法的功能,执行时可通过方法call()和apply()指定方法执行的环境,即关键字this所引用的对象。
  return core_slice.call( this );//slice() 方法用数组的某个片段切出新数组
 },
 get:function(num){  //get()转原生集合  get() 方法获得由选择器指定的 DOM 元素。
  //当get方法没有传参数时用toArray()方法将对象转换为真正的数组 
  //如果没有传入参数,则返回包含了所有元素的新数组
  //当get方法传参数时则返回一个单独的元素;参数index从0开始计算,并且支持负数,负数表示从元素集合末尾开始计算。
   return num == null ? this.toArray() : (num < 0 ? this[ this.length + num] :this[num] )
 },
 pushStack:function( elems ){ //jq对象的入栈处理
  //构造一个新的空jQuery对象ret,this.constructor指向构造函数函数jQuery,并把参数elems合并到jQuery对象ret中。
   var ret = jQuery.merge(this.constructor(),elems); //$.merge() 函数用于合并两个数组内容到第一个数组
  // 在新的jQuery对象ret上设置属性prevObject,指向当前jQuery对象,从而形成一个链式栈。
  //因此,方法.pushStack()的行为还可以理解为,
  //构建一个新的jQuery对象并入栈,新对象位于栈顶,这也是该方法如此命名的原因所在。
  ret.prevObject = this;//在新Query对象ret上设置属性prevObject,指向当前jQuery对象,从而形成一个链式栈
  ret.context = this.context;
  return ret;// 最后返回新jQuery对象ret。
 },
 //方法.each()遍历当前jQuery对象,并在每个元素上执行回调函数。
 //每当回调函数执行时,会传递当前循环次数作为参考,
 //循环次数从0开始计数;更重要的是,
 //回调函数是在当前元素为上下文的语境中触发的,
 //即关键字this总是指向当前元素;在回调函数中返回false可以终止遍历。
 each:function(callback, args){//each() :  遍历集合
  return jQuery.each(this,callback,args); //each() 方法规定为每个匹配元素规定运行的函数。
 },
 ready:function(fn){ //ready() :  DOM加载的接口
   jQuery.ready.promise().done(fn);
   return this;

 },
 slice:function(){ //slice() :  集合的截取
  //$("div").slice(1,3).css().end().css(),假设有4个div,那么第一个css只对第二个和第三个有效果,end之后,第二个css对这4个div都有效果。
 // .slice(start,[end])将匹配元素集合缩减为指定范围的子集
 //apply()应用某一对象的一个方法,用另一个对象替换当前对象。
    return this.pushStack(core_slice.apply(this,arguments));//4个div.pushStack(2个div)
 },
 first:function(){ //first()集合的第一项
   return this.eq(0);
 },
 last:function(){//last()集合的最后一项
   return this.eq(-1);
 },
 eq:function(i){ //eq() :   集合的指定项
  var len = this.length;
  j = +i + (i < 0 ? len :0);
  return this.pushStack(j >= 0 && j < len ? [this[j]] : []);
 },
 //map()遍历当前jQuery对象,在每个元素上执行回调函数,
 //并将回调函数的返回值放入一个新jQuery对象中。
 //该方法常用于获取或设置DOM元素集合的值。
 map:function(callback){ //map() :   返回新集合
  //$.map() 函数用于使用指定函数处理数组中的每个元素(或对象的每个属性),并将处理结果封装为新的数组返回
  // 执行回调函数时,关键字this指向当前元素。
  //回调函数可以返回一个独立的数据项或数据项数组,
  //返回值将被插入结果集中;如果返回一个数组,
  //数组中的元素会被插入结果集;如果回调函数返回null或undefined,则不会插入任何元素。
  return this.pushStack(jQuery.map(this,function(elem,i){
    return callback.call(elem,i,elem);
  }));
 },
 //end() 方法结束当前链条中的最近的筛选操作,并将匹配元素集还原为之前的状态。
 end:function(){ //返回集合前一个状态
  // 返回前一个jQuery对象。如果属性prevObject不存在,则构建一个空的jQuery对象返回。
  // 方法.pushStack()用于入栈。方法.end()则用于出栈。
     return this.prevObject || this.constructor();
 },
 // 方法.push(value,...)向当前jQuery对象的末尾添加新元素,并返回新长度。
 push:core_push,//push() 方法(在数组结尾处)向数组添加一个新的元素
 // 方法.sort([orderfunc])对当前jQuery对象中的元素进行排序,可以传入一个比较函数来指定排序方式。
 sort:[].sort,//数组的排序内部使用
 //方法.splice(start,deleteCount,value,...)向对前jQuery对象中插入、删除或替换元素。
 splice: [].splice //splice() 方法可删除从 index 处开始的零个或多个元素,并且用参数列表中声明的一个或多个值来替换那些被删除的元素。
 }       
// 2.给JQ对象添加一些方法和属性