jQuery構(gòu)造函數(shù)init參數(shù)分析續(xù)
如果selector是其他字符串情況就比較多了比較復(fù)雜了
// Handle HTML strings
if ( typeof selector === "string" ) {...}
開始分不同的情況處理
// 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里面先判斷第一個(gè)字符是“<”最后一個(gè)字符是“>”并且長(zhǎng)度大于3就假設(shè)此時(shí)的selector是html簡(jiǎn)單標(biāo)簽 ,比如$(‘<div>')但是記住僅僅是假設(shè)”assume”比如$(‘<sdfadfadf>')這樣的也會(huì)走這里。然后把match數(shù)組修改成[null,selector,null],這里的match是在init函數(shù)里面聲明的變量,主要是用來作為區(qū)分是參數(shù)類型的工具稍后在將可能情況列出,下面是源碼中聲明的四個(gè)變量
init: function( selector, context, rootjQuery ) {
var match, elem, ret, doc;
如果不滿足if的條件就會(huì)調(diào)用一個(gè)正則去得到match的結(jié)果,quickExpr是jQuery構(gòu)造函數(shù)里面聲明的變量
// 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\-]*)$)/,
這個(gè)正則主要是為了區(qū)別html字符串和id字符串的,第二個(gè)注釋中講到了為了避免基于 location.hash的 XSS 攻擊,于是在 quickExpr 中增加了 #(#9521)的意思是我們可以在jQuery官網(wǎng)找到相關(guān)解釋。
首先訪問http://bugs.jquery.com/然后搜索對(duì)應(yīng)的值即可
quickExpr.exec( selector )執(zhí)行的結(jié)果可以是一個(gè)數(shù)組,數(shù)組的第一個(gè)元素是匹配的元素,剩下的分別是分組匹配的元素,這個(gè)正則有兩個(gè)分組(<[\w\W]+>)[^>]和([\w\-]*)一個(gè)是標(biāo)簽一個(gè)是id值。最終會(huì)把結(jié)果交給match。下面就來分析下match的各種情況首先單標(biāo)簽不用正則式是 [ null, selector, null ]的形式,下面在代碼中證明:
<!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里面我們創(chuàng)建一個(gè)jQuery對(duì)象然后再init方法里面輸出得到的match結(jié)果:
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];
下面我們修改一下參數(shù)改為$(‘#div')然后再看一下結(jié)果
["#div", undefined, "div", index: 0, input: "#div"]
還有一種比較特殊的情況$(‘<div>123')然后我們?cè)倏匆幌陆Y(jié)果
["<div>dewrwe", "<div>", undefined, index: 0, input: "<div>dewrwe"]
我們可以看到id總是在第三個(gè)元素而標(biāo)簽值在第二個(gè)元素保存著,對(duì)于最后一種情況而言跟$(‘<div>')是沒有什么區(qū)別的因?yàn)樯蒬om元素時(shí)是不會(huì)處理第一個(gè)元素的?;谶@個(gè)結(jié)果可以接著來分析下一個(gè)判斷了。
接下來的會(huì)根據(jù)match的結(jié)果分為三種情況
if ( match && (match[1] || !context) ) {
...
} else if ( !context || context.jquery ) {
...
} else {
...
}
第一種情況滿足的條件是match一定要有值,match[1]就是第二個(gè)元素就是保存標(biāo)簽的這個(gè)有值或者不存在上下文,但是好像沒有id什么事???其實(shí)不是的通過分析match的結(jié)果可以知道第二個(gè)元素沒有值肯定就是id選擇器得到的結(jié)果,而id是唯一的,不需要寫上下文(其實(shí)寫了上下文也會(huì)正常執(zhí)行只不過會(huì)使用Sizzle而不是在這里處理了跟body是一樣的)。好了第一個(gè)條件進(jìn)來的情況就是
1.標(biāo)簽
$(‘<div>') $(‘<div>123') $(‘<div>23213213</div>')...
2.沒有上下文的id $(‘#div')
第一個(gè)條件內(nèi)部又進(jìn)行了細(xì)分:
// HANDLE: $(html) -> $(array)
if ( match[1] ) {
...
// HANDLE: $("#id")
}else{
}
很顯然if是處理標(biāo)簽的else是處理id的,先來看看是怎么處理標(biāo)簽的吧
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對(duì)象就把他變成dom元素就是使用下標(biāo)的方法這個(gè)原理之前說過了,然后有處理了doc變量,如果context不存在就把document賦值給doc如果存在且有ownerDocument屬性那就是dom元素了這個(gè)值還是document如果不是dom元素比如普通的js對(duì)象的話那就把這個(gè)對(duì)象賦值給doc變量。緊接著對(duì)selector又進(jìn)行了一個(gè)正則判斷,這個(gè)正則也是在jQuery構(gòu)造函數(shù)里面聲明的目的是判斷單標(biāo)簽 比如<div>這樣的
// Match a standalone tag
rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
然后把結(jié)果交給ret變量,基于ret的值又進(jìn)行劃分按照單標(biāo)簽和復(fù)雜標(biāo)簽分開處理ret值存在那就是匹配到了單標(biāo)簽然后再根據(jù)context是不是普通對(duì)象又分為兩種情況isPlainObject是檢測(cè)是不是普通對(duì)象的方法,如果是普通對(duì)象,就利用js原生方法createElement傳入標(biāo)簽創(chuàng)建元素并放在一個(gè)數(shù)組里面,之所以這樣是為了以后跟jquery對(duì)象合并方便,然后把數(shù)組賦值給selector,后采用對(duì)象冒充的方法調(diào)用attr方法,這里attr居然有3個(gè)參數(shù),而平常我們使用的api里面是兩個(gè)參數(shù),其實(shí)jQuery中有很多類似的情況,同樣的方法有著對(duì)內(nèi)對(duì)外兩個(gè)接口。第二個(gè)參數(shù)就是對(duì)象形式的上下文,因?yàn)閍ttr可以像
$("img").attr({ src: "test.jpg", alt: "Test Image" });
這給我們的其實(shí)就是我們以后可以$(‘<div>',{id:'div'})這樣寫了也是支持的。如果不是對(duì)象就直接創(chuàng)建元素不考慮屬性。還是把創(chuàng)建的元素放在數(shù)組里面。如果ret沒有值那就是復(fù)雜的標(biāo)簽了比如$(‘<div>231</div>')這樣的這個(gè)時(shí)候原生的js就搞不定啦需要調(diào)取另外一個(gè)方法jQuery.buildFragment來處理,這個(gè)方法實(shí)現(xiàn)以后在學(xué)習(xí)吧,總之最后都會(huì)創(chuàng)建dom元素。最后返回合并后的結(jié)果
return jQuery.merge( this, selector );
不像之前的return this這里是返回merge執(zhí)行后的結(jié)果其實(shí)他的任務(wù)就是把放在數(shù)組里面的創(chuàng)建好的的dom元素合并到j(luò)query元素中去,最終變成{0:div,length:1...}這樣的對(duì)象形式。這樣的話簡(jiǎn)標(biāo)簽情況就處理完畢。
然后else里面處理的是id的情況
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;
很簡(jiǎn)單直接調(diào)用原生js的id選擇器但是有一些系統(tǒng)會(huì)出現(xiàn)bug
注釋說的很清楚黑莓系統(tǒng),就是元素已經(jīng)不存在了但是依然能夠匹配得到所以再加上父節(jié)點(diǎn),不存在的元素肯定沒有父節(jié)點(diǎn)的。還有一種情況就是ie和opera瀏覽器會(huì)出現(xiàn)按name值匹配的情況所以在做了一個(gè)判斷
if ( elem.id !== match[2] ) {
如果真的不幸出現(xiàn)了那就不能使用原生方法而是用find方法也就是使用sizzle引擎了,在大多數(shù)正常情況下就直接將獲取到的元素放到this里面就可以啦然后修改下context的值。Ok終于把第一個(gè)大分支分析完了。然后再看根據(jù)match的第二個(gè)分支
else if ( !context || context.jquery ) {
return ( context || rootjQuery ).find( selector );
}
這里是如果沒有上下文或者上下文是jquery對(duì)象的時(shí)候這個(gè)比較簡(jiǎn)單就是直接用find方法了rootjQuery 就是$(document)
最后字符串的情況上面都不屬于的話
return this.constructor( context ).find( selector );
This.constructor就是jQuery其實(shí)還是使用find方法。
以上所述就是本文的全部?jī)?nèi)容了,希望大家能夠喜歡。
相關(guān)文章
學(xué)習(xí)從實(shí)踐開始之jQuery插件開發(fā) 對(duì)話框插件開發(fā)
之所以寫下這篇文章,是想將我的想法分享給大家;對(duì)于初學(xué)者,我希望他能從這篇文章中獲取對(duì)他有用的東西,對(duì)于經(jīng)驗(yàn)豐富的開發(fā)者,我希望他能指出我的不足,給我更多的意見和建議;目的就是共同進(jìn)步2012-04-04
jquery實(shí)現(xiàn)可拖動(dòng)DIV自定義保存到數(shù)據(jù)的實(shí)例
這篇文章主要介紹了jquery實(shí)現(xiàn)可拖動(dòng)DIV自定義保存到數(shù)據(jù),有需要的朋友可以參考一下2013-11-11
JQuery中使用ajax傳輸超大數(shù)據(jù)的解決方法
這篇文章主要介紹了JQuery中使用ajax傳輸超大數(shù)據(jù)的解決方法,也就是比較多的數(shù)據(jù),超過max_upload_size等設(shè)置,本文方法在chrome瀏覽器下測(cè)試通過,需要的朋友可以參考下2014-07-07
jQuery 自動(dòng)增長(zhǎng)的文本輸入框?qū)崿F(xiàn)代碼
文本輸入框內(nèi)的字?jǐn)?shù)不能確定,而input type="text"的size是固定的,當(dāng)字?jǐn)?shù)超過size時(shí)(默認(rèn)是20),先輸入的內(nèi)容就會(huì)從文本框的左端隱藏起來,不便于輸入。2010-04-04
jQuery實(shí)現(xiàn)簡(jiǎn)單登錄條件判斷
這篇文章主要為大家詳細(xì)介紹了jQuery實(shí)現(xiàn)簡(jiǎn)單登錄條件判斷,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
jQuery Easyui 驗(yàn)證兩次密碼輸入是否相等
easyui是一種基于jQuery的用戶界面插件集合。接下來通過本文給大家介紹jQuery Easyui 驗(yàn)證兩次密碼輸入是否相等的相關(guān)知識(shí),感興趣的朋友一起學(xué)習(xí)吧2016-05-05

