jQuery源碼學習(2):選擇器初窺

選擇器初窺

代碼架構:

jQuery選擇器能夠依照傳入數據的類型分爲五大類:html

  • 傳入字符串:$("div"), $("#id"), $(".div1"),$(".div p.title")
  • 傳入html代碼:$("<div></div>"), $("<div>1</div><div>2</div>")
  • 傳入對象:$(document), $(this)
  • 傳入數組或對象字面量:$({}), $([])
  • 傳入函數:$(function(){})

下面咱們來看一下jQuery構造函數代碼(jQuery-2.2.2第2832行起)的架構:node

jQuery.fn.init = function(selector, context){
  if(!selector){

    // part1.處理$(null), $(undefined), $(false), $("")

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

    // part2.匹配selector並將結果傳入match中 

  }
    if(match && (match[1] || !context)){

      // part3.建立標籤或按#id查詢


    }else{

      // part4.處理複雜選擇器

    }
  }
  // 一些其餘的不常見狀況
  else {...}
  return jQuery.makeArray(selector, this);
}

能夠發現jQ將代碼依照selector的類型分爲了幾個部分。下面咱們來依次分析這幾部分的代碼。jquery

 

第一部分:檢測沒有傳入值的狀況

此段完整代碼以下:正則表達式

// HANDLE: $(""), $(null), $(undefined), $(false)
if ( !selector ) {
  return this;
}

 

第二部分:匹配傳入的字符串

此段完整代碼以下:數組

if ( selector[ 0 ] === "<" &&selector[ selector.length - 1 ] === ">" &&selector.length >= 3 ) {
  // Assume that strings that start and end with <> are HTML and skip the regex check
  match = [ null, selector, null ];
} else {
  match = rquickExpr.exec( selector );
}
// 匹配html標籤或#id
rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,

 

經過分析rquickExpr正則表達式,咱們能夠得出在selector分別爲如下幾種值時返回值match的結構:架構

1. selector = "<div>"函數

match = [null, "<div>", null]

2. selector = "<div>content</div>"ui

match = [null, "<div>content</div>", null]

3. selector = "<div></div>content"this

match = ["<div></div>content", "<div></div>", null]

4. selector = #idspa

match = [#id, null, #id]

 

第三部分:建立標籤或者按#id查詢

傳入標籤時:

此段完整代碼以下:

// 若是是html標籤
  if ( match[ 1 ] ) {
// 若是傳入的context是jQ對象,將其轉換成原生對象
    context = context instanceof jQuery ? context[0] : context;

// 將傳入的html字符串轉換成節點數組並傳入this中
    jQuery.merge(this, jQuery.parseHTML(match[1], context && context.nodeType ? context.ownerDocument || context : document, true));

// 若是是$(html, props)的形式,則要設置對應屬性或執行方法
    if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
      for (match in context) {

// 若 prop 的某一項是jQ方法
        if (jQuery.isFunction(this[match])) {
          this[match](context[match]);

// 不然設置對應屬性
        } else {
          this.attr(match, context[match]);
        }
      }
    }

    return this;
  }
// 匹配單標籤
var rsingleTag = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ );

 

關鍵位置的語意都已在註釋中講解過了,下面主要介紹一下$.parseHTML和$.merge這兩個方法在其中的應用:

jQuery.parseHTML( data [, context ] [, keepScripts ] )
  • data:須要被轉換成節點的字符串
  • context:被轉換的節點所存在的上下文。並無太大用處,默認是document,在須要在iframe中進行操做時,也能夠設成contentWindow。
  • keepScripts:布爾值。設置成true時容許將字符串中的<script>部分也轉換成節點。

 

jQuery.merge(first, second)

咱們常常用$.merge來進行數組的合併。在本例中須要強調的一點是,$.merge被用來將一個數組合併到類數組對象中。就像下面這樣:

  var obj = {0: "hello", 1: "pansy", length: 2};
  var arr = ["from", "arr"];

  console.log($.merge(obj, arr));   // Object {0: "hello", 1: "pansy", 2: "from", 3: "arr", length: 4}

 

傳入id時:

// HANDLE: $(#id)
else {
  elem = document.getElementById( match[ 2 ] );

  // Support: Blackberry 4.6
  // gEBID returns nodes 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;
}

 

第四部分:處理複雜選擇器

// 處理形如$(".class"), $("ul li+p")等等
if ( !context || context.jquery ) {
  return ( context || root ).find( selector );

// 當傳入上下文是原生對象時,調用構造函數返回jQ對象
} else {
  return this.constructor( context ).find( selector );
}

此處複雜選擇器所有藉助$().find()方法實現,使用了sizzle引擎,咱們稍後再進行介紹。

相關文章
相關標籤/搜索