jQuery建構函式init參數分析續

來源:互聯網
上載者:User

jQuery建構函式init參數分析續

   其實樓主的F和jQuery.fn.init是相等的; 實現功能是和jq一樣的, 只是jq的把建構函式放進原型;如果非要說原因,個人理解jq這樣寫整體結構清晰,先是入口建構函式,緊跟著是原型部分(原型裡面init是初始化),但是不好理解;乍一看確實挺繞, 我也是看了好久才明白怎麼回事

  如果selector是其他字串情況就比較多了比較複雜了

  ?

1

2

// Handle HTML strings

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

  開始分不同的情況處理

  ?

1

2

3

4

5

6

7

// Are we dealing with HTML string or an ID?

if ( selector.charAt(0) === "<" && selector.charAt( 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 = quickExpr.exec( selector );

}

  If裡面先判斷第一個字元是“<”最後一個字元是“>”並且長度大於3就假設此時的selector是html簡單標籤 ,比如$(‘

')但是記住僅僅是假設”assume”比如$(‘')這樣的也會走這裡。然後把match數組修改成[null,selector,null],這裡的match是在init函數裡面聲明的變數,主要是用來作為區分是參數類型的工具稍後在將可能情況列出,下面是源碼中聲明的四個變數

 

  ?

1

2

init: function( selector, context, rootjQuery ) {

var match, elem, ret, doc;

  如果不滿足if的條件就會調用一個正則去得到match的結果,quickExpr是jQuery建構函式裡面聲明的變數

  ?

1

2

3

// A simple way to check for HTML strings or ID strings

// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)

quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,

  這個正則主要是為了區別html字串和id字串的,第二個注釋中講到了為了避免基於 location.hash的 XSS 攻擊,於是在 quickExpr 中增加了 #(#9521)的意思是我們可以在jQuery官網找到相關解釋。

  首先訪問http://bugs.jquery.com/然後搜尋對應的值即可

  quickExpr.exec( selector )執行的結果可以是一個數組,數組的第一個元素是匹配的元素,剩下的分別是分組匹配的元素,這個正則有兩個分組(<[\w\W]+>)[^>]和([\w\-]*)一個是標籤一個是id值。最終會把結果交給match。下面就來分析下match的各種情況首先單標籤不用正則式是 [ null, selector, null ]的形式,下面在代碼中證明:

  ?

1

2

3

4

5

6

7

8

9

10

11

12

13

<!doctype html>

<html>

<head>

<title></title>

<script src='jquery-1.7.1.js'></script>

</head>

<body>

<div id='div'></div>

</body>

<script>

$('<div>');

</script>

</html>

  在html裡面我們建立一個jQuery對象然後再init方法裡面輸出得到的match結果:

  ?

1

2

3

4

5

6

7

if ( selector.charAt(0) === "<" && selector.charAt( 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 = quickExpr.exec( selector );

}

console.log(match); // [null, "<div>", null];

  下面我們修改一下參數改為$(‘#div')然後再看一下結果

   代碼如下:

  ["#div", undefined, "div", index: 0, input: "#div"]

  還有一種比較特殊的情況$(‘

123')然後我們再看一下結果

 

  代碼如下:

  ["

dewrwe", "

", undefined, index: 0, input: "

dewrwe"]

 

  我們可以看到id總是在第三個元素而標籤值在第二個元素儲存著,對於最後一種情況而言跟$(‘

')是沒有什麼區別的因為產生dom元素時是不會處理第一個元素的。基於這個結果可以接著來分析下一個判斷了。

 

  接下來的會根據match的結果分為三種情況

  ?

1

2

3

4

5

6

7

8

9

10

11

12

13

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

 

...

 

} else if ( !context || context.jquery ) {

 

...

 

} else {

 

...

 

}

  第一種情況滿足的條件是match一定要有值,match[1]就是第二個元素就是儲存標籤的這個有值或者不存在上下文,但是好像沒有id什麼事啊?其實不是的通過分析match的結果可以知道第二個元素沒有值肯定就是id選取器得到的結果,而id是唯一的,不需要寫上下文(其實寫了上下文也會正常執行只不過會使用Sizzle而不是在這裡處理了跟body是一樣的)。好了第一個條件進來的情況就是

  1.標籤

  $(‘

') $(‘

123') $(‘

23213213

')...

 

  2.沒有內容相關的id $(‘#div')

  第一個條件內部又進行了細分:

  ?

1

2

3

4

5

6

7

8

9

10

// HANDLE: $(html) -> $(array)

if ( match[1] ) {

 

...

 

// HANDLE: $("#id")

 

}else{

 

}

  很顯然if是處理標籤的else是處理id的,先來看看是怎麼處理標籤的吧

  ?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

context = context instanceof jQuery ? context[0] : context;

doc = ( context ? context.ownerDocument || context : document );

 

// If a single string is passed in and it's a single tag

// just do a createElement and skip the rest

ret = rsingleTag.exec( selector );

 

if ( ret ) {

if ( jQuery.isPlainObject( context ) ) {

selector = [ document.createElement( ret[1] ) ];

jQuery.fn.attr.call( selector, context, true );

 

} else {

selector = [ doc.createElement( ret[1] ) ];

}

 

} else {

ret = jQuery.buildFragment( [ match[1] ], [ doc ] );

selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;

}

 

return jQuery.merge( this, selector);

  首先修正一下context的值,如果是jQuery對象就把他變成dom元素就是使用下標的方法這個原理之前說過了,然後有處理了doc變數,如果context不存在就把document賦值給doc如果存在且有ownerDocument屬性那就是dom元素了這個值還是document如果不是dom元素比如普通的js對象的話那就把這個對象賦值給doc變數。緊接著對selector又進行了一個正則判斷,這個正則也是在jQuery建構函式裡面聲明的目的是判斷單標籤 比如

這樣的

 

  代碼如下:

  // Match a standalone tag

  rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,

  然後把結果交給ret變數,基於ret的值又進行劃分按照單標籤和複雜標籤分開處理ret值存在那就是匹配到了單標籤然後再根據context是不是普通對象又分為兩種情況isPlainObject是檢測是不是普通對象的方法,如果是普通對象,就利用js原生方法createElement傳入標籤建立元素並放在一個數組裡面,之所以這樣是為了以後跟jquery對象合并方便,然後把數組賦值給selector,後採用對象冒充的方法調用attr方法,這裡attr居然有3個參數,而平常我們使用的api裡面是兩個參數,其實jQuery中有很多類似的情況,同樣的方法有著對內對外兩個介面。第二個參數就是對象形式的上下文,因為attr可以像

   代碼如下:

  $("img").attr({ src: "test.jpg", alt: "Test Image" });

  這給我們的其實就是我們以後可以$(‘

',{id:'div'})這樣寫了也是支援的。如果不是對象就直接建立元素不考慮屬性。還是把建立的元素放在數組裡面。如果ret沒有值那就是複雜的標籤了比如$(‘

231

')這樣的這個時候原生的js就搞不定啦需要調取另外一個方法jQuery.buildFragment來處理,這個方法實現以後在學習吧,總之最後都會建立dom元素。最後返回合并後的結果

 

   代碼如下:

  return jQuery.merge( this, selector );

  不像之前的return this這裡是返回merge執行後的結果其實他的任務就是把放在數組裡面的建立好的的dom元素合并到jquery元素中去,最終變成{0:div,length:1...}這樣的對象形式。這樣的話簡標籤情況就處理完畢。

  然後else裡面處理的是id的情況

  ?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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 ) {

// Handle the case where IE and Opera return items

// by name instead of ID

if ( elem.id !== match[2] ) {

return rootjQuery.find( selector );

}

// Otherwise, we inject the element directly into the jQuery object

this.length = 1;

this[0] = elem;

}

this.context = document;

this.selector = selector;

return this;

  很簡單直接調用原生js的id選取器但是有一些系統會出現bug

  注釋說的很清楚黑莓系統,就是元素已經不存在了但是依然能夠匹配得到所以再加上父節點,不存在的元素肯定沒有父節點的。還有一種情況就是ie和opera瀏覽器會出現按name值匹配的情況所以在做了一個判斷

  if ( elem.id !== match[2] ) {

  如果真的不幸出現了那就不能使用原生方法而是用find方法也就是使用sizzle引擎了,在大多數正常情況下就直接將擷取到的元素放到this裡面就可以啦然後修改下context的值。Ok終於把第一個大分支分析完了。然後再看根據match的第二個分支

  ?

1

2

3

else if ( !context || context.jquery ) {

return ( context || rootjQuery ).find( selector );

}

  這裡是如果沒有上下文或者上下文是jquery對象的時候這個比較簡單就是直接用find方法了rootjQuery 就是$(document)

  最後字串的情況上面都不屬於的話

   代碼如下:

  return this.constructor( context ).find( selector );

  This.constructor就是jQuery其實還是使用find方法。

  以上所述就是本文的全部內容了,希望大家能夠喜歡。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.