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原文链接

  • 相关阅读:
    Leetcode Plus One
    Leetcode Swap Nodes in Pairs
    Leetcode Remove Nth Node From End of List
    leetcode Remove Duplicates from Sorted Array
    leetcode Remove Element
    leetcode Container With Most Water
    leetcode String to Integer (atoi)
    leetcode Palindrome Number
    leetcode Roman to Integer
    leetcode ZigZag Conversion
  • 原文地址:https://www.cnblogs.com/yangjunhua/p/2853558.html
Copyright © 2011-2022 走看看