zoukankan      html  css  js  c++  java
  • 深入分析jQuery.prototype.init选择器源码

    一、源码思路分析总结

    [ 作者:华子yjh ]

    概要:

    jQuery的核心思想可以简单概括为“查询和操作dom”,今天主要是分析一下jQuery.prototype.init选择器构造函数,处理选择器函数中的参数;

    这个函数的参数就是jQuery()===$()执行函数中的参数,可以先看我之前写的浅析jQuery基础框架一文,了解基础框架后,再看此文。


    思路分析:

    以下是几种jQuery的使用情况(用于查询dom),每种情况都返回一个选择器实例(习惯称jQuery对象(一个nodeList对象),该对象包含查询的dom节点):

    1、处理 $(""), $(null), $(undefined), $(false)

    如果参数为以上非法值,jQuery对象不包含dom节点


    2、处理 $(DOMElement)

    如果参数为节点元素,jQuery对象包含该参数节点元素,并分别增加属性值为参数节点元素、1的context、length属性和用[]访问jQuery对象中dom节点的用法

    例2.1:

    1 var obj = document.getElementById('container'),
    2 jq = $(obj);
    3 
    4 console.log(jq.length); //1
    5 console.log(jq.context); //obj
    6 console.log(jq.[0]); //obj


    3、处理$(HTML字符串)

    如果第一个参数为HTML字符串,jQuery对象包含由jQuery.clean函数创建的fragment文档碎片中的childnodes节点

    例3.1:

    1 var jqHTML = $('<h1>文章标题</h1><p>内容</p>');
    2 console.log(jqHTML); //[<h1>,<p>];

    如果第一个参数(HTML字符串)为一个空的单标签,且第二个参数context为一个非空纯对象

    例3.2:

    1 var jqHTML = $('<div></div>', { class: 'css-class', data-name: 'data-val' });
    2 
    3 console.log(jqHTML.attr['class']); //css-class
    4 console.log(jqHTML.attr['data-name']); //data-val


    4、处理$(#id)

    如果第一个参数是一个#加元素id,jQuery对象包含唯一拥有该id的元素节点,
    并分别增加属性值为document、参数字符串、1、的context、selector、length属性和用[]访问jQuery对象中dom节点的用法

    例4.1:

    1 var jq = $('#container');
    2 
    3 console.log(jq.[0]); //包含的dom节点元素
    4 console.log(jq.length); //1
    5 console.log(jq.context); //document
    6 console.log(jq.selector); //container


    5、处理$(.className)

    如果第一个参数是一个.className,jQuery对象中拥有class名为className的标签元素,并增加一个属性值为参数字符串、document的selector、context属性

    实际执行代码为:

    1 return jQuery(document).find(className);


    6、处理$(.className, context)

    如果第一个参数是.className,第二个参数是一个上下文对象(可以是.className(等同于处理$(.className .className)),jQuery对象或dom节点),
    jQuery对象包含第二个参数上下文对象中拥有class名为className的后代节点元素,并增加一个context和selector属性

    实际执行代码为:

    1 return jQuery(context).find(className);

    例6.1:

    html代码:

    1 <div class="main">
    2 <h2 class="title">主内容标题</h2>
    3 <p>主标题</p>
    4 </div>
    5 
    6 <div class="sub">
    7 <h2 class="title">次内容标题</h2>
    8 <p>次标题</p>
    9 </div>

    JavaScript代码:

     1 var jq, context;
     2 
     3 context = '.sub';
     4 var jq = $('.title', context);
     5 console.log(jq.text()); //次内容标题
     6 console.log(jq.context); //document
     7 console.log(jq.selector); //.sub .title
     8 
     9 context = $('.sub');
    10 var jq = $('.title', context);
    11 console.log(jq.text()); //次内容标题
    12 console.log(jq.context); //document
    13 console.log(jq.selector); //.sub .title
    14 
    15 context = $('.sub')[0];
    16 var jq = $('.title', context);
    17 console.log(jq.text()); //次内容标题
    18 console.log(jq.context); //className为sub的节点元素
    19 console.log(jq.selector); //.title
    
    

    7、处理$(fn)

    如果第一个参数是fn函数,则调用$(document).ready(fn);

    例7.1:

    1 $(function(e){
    2     console.log('DOMContent is loaded');
    3 })
    4 //上面代码等同于:
    5 jQuery(document).ready(function(e) {
    6     console.log('DOMContent is loaded');
    7 });

    8、处理$(jQuery对象)

    如果第一个参数是jQuery对象,上面已经分析过如果在查询dom时,参数是一个#加元素id,返回的jQuery对象会增加一个属性值为参数字符串、document的selector、context属性

    例8.1:

    1 var jq = $('#container');
    2 console.log(jq.selector); // #container
    3 console.log(jq.context); // document

    那么当出现$($('#container'))该如何处理呢?同样的,返回的jQuery对象同情况5和6处理的情况一样

    例8.2:

    1 var jq2 = $($('#container'));
    2 console.log(jq2.selector); // #container
    3 console.log(jq2.context); // document

    二、源码注释分析

    [ 基于jQuery1.8.3 ]

      1 var rootjQuery = $(document),
      2     rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/;    
      3 
      4 jQuery.fn = jQuery.prototype = {
      5     init: function( selector, context, rootjQuery ) {
      6         var match, elem, ret, doc;
      7 
      8         // Handle $(""), $(null), $(undefined), $(false)
      9         if ( !selector ) {
     10             return this;
     11         }
     12 
     13         // Handle $(DOMElement)
     14         if ( selector.nodeType ) {
     15             this.context = this[0] = selector;
     16             this.length = 1;
     17             return this;
     18         }
     19 
     20         // Handle HTML strings
     21         if ( typeof selector === "string" ) {
     22             if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
     23                 // Assume that strings that start and end with <> are HTML and skip the regex check
     24                 match = [ null, selector, null ];
     25 
     26             } else {
     27                 match = rquickExpr.exec( selector );
     28             }
     29 
     30             // Match html or make sure no context is specified for #id
     31             // match[1]不为null,则为html字符串,match[2]不为null,则为元素id
     32             if ( match && (match[1] || !context) ) {
     33 
     34                 // HANDLE: $(html) -> $(array)
     35                 if ( match[1] ) {
     36                     context = context instanceof jQuery ? context[0] : context;
     37                     doc = ( context && context.nodeType ? context.ownerDocument || context : document );
     38 
     39                     // scripts is true for back-compat
     40                     // selector是由文档碎片中的childnodes组成的数组
     41                     selector = jQuery.parseHTML( match[1], doc, true );
     42                     
     43                     // 如果match[1]为空的单标签元素(如:<div><div>)且context为对象字面量
     44                     if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
     45                         
     46                         // 如果context对象不为空,则将对象中的属性添加到selector数组中仅有的dom节点中
     47                         this.attr.call( selector, context, true );
     48                     }
     49                     
     50                     // merge函数的参数应该为两个数组,目的是将第二个数组中的项合并到第一个数组,而this并不是一个数组,
     51                     // this是选择器init构造函数的实例对象,该对象继承jQuery.prototype对象中的length属性(默认为0),因此可以理解好merge函数源码
     52                     // 将selector中的dom项合并到this对象中,并返回该对象
     53                     return jQuery.merge( this, selector );
     54 
     55                 // HANDLE: $(#id)
     56                 } else {
     57                     elem = document.getElementById( match[2] );
     58 
     59                     // Check parentNode to catch when Blackberry 4.6 returns
     60                     // nodes that are no longer in the document #6963
     61                     if ( elem && elem.parentNode ) {
     62                         // Handle the case where IE and Opera return items
     63                         // by name instead of ID
     64                         // ie6,7和Opera存在此bug,当一个标签name和一个标签id值相等时,
     65                         // document.getElementById(#id)函数将返回提前出现的标签元素
     66                         if ( elem.id !== match[2] ) {
     67                             // 如果存在以上Bug,则返回由find函数返回的document文档的后代元素集合
     68                             return rootjQuery.find( selector );
     69                         }
     70 
     71                         // Otherwise, we inject the element directly into the jQuery object
     72                         this.length = 1;
     73                         this[0] = elem;
     74                     }
     75 
     76                     this.context = document;
     77                     this.selector = selector;
     78                     return this;
     79                 }
     80 
     81             // HANDLE: $(expr, $(...))
     82             // context不存在或者context为jQuery对象
     83             } else if ( !context || context.jquery ) {
     84                 return ( context || rootjQuery ).find( selector );
     85 
     86             // HANDLE: $(expr, context)
     87             // (which is just equivalent to: $(context).find(expr)
     88             // context为className或者dom节点元素
     89             } else {
     90                  // 等同于jQuery(context).find(selector)
     91                 return this.constructor( context ).find( selector );
     92             }
     93 
     94         // 处理$(fn)===$(document).ready(fn)
     95         } else if ( jQuery.isFunction( selector ) ) {
     96             return rootjQuery.ready( selector );
     97         }
     98         
     99         // 处理$(jQuery对象)
    100         if ( selector.selector !== undefined ) {
    101             this.selector = selector.selector;
    102             this.context = selector.context;
    103         }
    104 
    105         // 当第一个参数selector为jQuery对象时,将selector中的dom节点合并到this对象中,并返回this对象
    106         return jQuery.makeArray( selector, this );
    107     }
    108 }

    转载请注明出处【作者:华子yjh原文链接

  • 相关阅读:
    shell数组
    正则表达式整数
    云计算的三种服务模式(IaaS/PaaS/SaaS)
    云计算通信协议
    LVS 核心组件和专业术语
    nginx
    【转】mybatis调用mssql有输入输出参数那种..
    OAuth2.0 在 SSO中的应用~
    Git 本地安装
    【转】Android开发之ListView+EditText-要命的焦点和软键盘问题解决办法
  • 原文地址:https://www.cnblogs.com/yangjunhua/p/2853558.html
Copyright © 2011-2022 走看看