jQuery選擇器的工作原理和優(yōu)化分析
更新時(shí)間:2011年07月25日 00:29:54 作者:
至于有那些選擇器,在幫助手冊(cè)中都有,自己去看,這篇主要是分析他的工作原理,而優(yōu)化我們寫 的選擇器,尤其在頁面內(nèi)容很多的情況下,更應(yīng)該需要優(yōu)化。下邊就言歸正傳。
每次申明一個(gè)jQuery對(duì)象的時(shí)候,返回的是jQuery.prototype.init 對(duì)象,很多人就會(huì)不明白,init明明是jQuery.fn的方法啊,實(shí)際上這里不是方法,而是init的構(gòu)造函數(shù),因?yàn)閖s的prototype對(duì)象可 以實(shí)現(xiàn)繼承,加上js的對(duì)象只是引用不會(huì)是拷貝,new jQuery,new jQuery.fn和new jQuery.fn.init的子對(duì)象是一樣的,只是有沒有執(zhí)行到init的不同,這里就不講原因了,等下一篇再講為什么會(huì)是這樣。
當(dāng)我們使用選擇器的時(shí)候$(selector,content),就會(huì)執(zhí)行 init(selectot,content),我們看看inti中是怎樣執(zhí)行的:
if ( typeof selector == "string" ) {
//正則匹配,看是不是HTML代碼或者是#id
var match = quickExpr.exec( selector );
//沒有作為待查找的 DOM 元素集、文檔或 jQuery 對(duì)象。
//selector是#id的形式
if ( match && (match[1] || !context) ) {
// HANDLE: $(html) -> $(array)
//HTML代碼,調(diào)用clean補(bǔ)全HTML代碼
if ( match[1] ){
selector = jQuery.clean( [ match[1] ], context );
}
// 是: $("#id")
else {
//判斷id的Dom是不是加載完成
var elem = document.getElementById( match[3] );
if ( elem ){
if ( elem.id != match[3] )
return jQuery().find( selector );
return jQuery( elem );//執(zhí)行完畢return
}
selector = [];
}
//非id的形式.在context中或者是全文查找
} else{
return jQuery( context ).find( selector );
}
}
這里就說明只有選擇器寫成$(‘#id')的時(shí)候最快,相當(dāng)于執(zhí)行了一次 getElementById,后邊的程序就不用再執(zhí)行了。當(dāng)然往往我們需要的選擇器并不是這么簡(jiǎn)單,比如我們需要id下的CSS為className, 有這樣的寫法$(‘#id.className')和$(‘#id').find(‘.className');這兩種寫法的執(zhí)行結(jié)果都是一樣的,比 如<div id=”id”><span class=”className”></span></div>,返回的肯定都是<span class=”className”></span>,但是執(zhí)行的效率是完全不一樣的。
在分析一下上邊的代碼,如果不是$(‘#id')這樣的簡(jiǎn)單選擇器的話,都會(huì)執(zhí)行find函 數(shù),那我們?cè)倏纯磃ind到底是做用的:
find: function( selector ) {
//在當(dāng)前的對(duì)象中查找
var elems = jQuery.map(this, function(elem){
return jQuery.find( selector, elem );
});
//下邊的代碼可以忽略,只是做一些處理
//這里應(yīng)用了js的正則對(duì)象的靜態(tài)方法test
//indexOf("..")需要了解一下xpath的語法,就是判斷selector中包含父節(jié)點(diǎn)的寫法
//本意就是過濾數(shù)組的重復(fù)元素
return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ?
jQuery.unique( elems ) :
elems );
}
如果這樣寫$(‘#id .className'),就會(huì)執(zhí)行到擴(kuò)展的find(‘#id .className',document),因?yàn)楫?dāng)前的this是document的jQuery數(shù)組,那我們?cè)诳纯磾U(kuò)展的find他的實(shí)現(xiàn),代碼比較 多,就不列出來,總之就是從第二個(gè)參數(shù)傳遞進(jìn)行的dom第一個(gè)子節(jié)點(diǎn)開始找,遇見#比對(duì)id,遇見.比對(duì)ClassName,還有:<+-等處理。 那我們要優(yōu)化,是不是就要想辦法讓第二個(gè)參數(shù)context的范圍最小,那樣遍歷是不是就很少了?
如果我們這樣寫$(‘#id').find(‘.className'),那程序只這樣執(zhí)行 的,第一次init的時(shí)候執(zhí)行一步getElementById,就return了,接著執(zhí)行 find(‘.className',divDocument),divDocument就是我們第一次選擇的是div標(biāo)簽,如果document下有很 多dom對(duì)象的時(shí)候,這次只遍歷divDocument是不是少了很多次,而且在第一次選擇id的速度也要比遍歷快的多。
現(xiàn)在大家應(yīng)該是明白了吧。就是說第一層選擇最好是ID,而是簡(jiǎn)單選擇器,目的就是定義范圍, 提高速度,這次就說這些,選擇寫法的優(yōu)化,其他的優(yōu)化,下次再說。
當(dāng)我們使用選擇器的時(shí)候$(selector,content),就會(huì)執(zhí)行 init(selectot,content),我們看看inti中是怎樣執(zhí)行的:
復(fù)制代碼 代碼如下:
if ( typeof selector == "string" ) {
//正則匹配,看是不是HTML代碼或者是#id
var match = quickExpr.exec( selector );
//沒有作為待查找的 DOM 元素集、文檔或 jQuery 對(duì)象。
//selector是#id的形式
if ( match && (match[1] || !context) ) {
// HANDLE: $(html) -> $(array)
//HTML代碼,調(diào)用clean補(bǔ)全HTML代碼
if ( match[1] ){
selector = jQuery.clean( [ match[1] ], context );
}
// 是: $("#id")
else {
//判斷id的Dom是不是加載完成
var elem = document.getElementById( match[3] );
if ( elem ){
if ( elem.id != match[3] )
return jQuery().find( selector );
return jQuery( elem );//執(zhí)行完畢return
}
selector = [];
}
//非id的形式.在context中或者是全文查找
} else{
return jQuery( context ).find( selector );
}
}
這里就說明只有選擇器寫成$(‘#id')的時(shí)候最快,相當(dāng)于執(zhí)行了一次 getElementById,后邊的程序就不用再執(zhí)行了。當(dāng)然往往我們需要的選擇器并不是這么簡(jiǎn)單,比如我們需要id下的CSS為className, 有這樣的寫法$(‘#id.className')和$(‘#id').find(‘.className');這兩種寫法的執(zhí)行結(jié)果都是一樣的,比 如<div id=”id”><span class=”className”></span></div>,返回的肯定都是<span class=”className”></span>,但是執(zhí)行的效率是完全不一樣的。
在分析一下上邊的代碼,如果不是$(‘#id')這樣的簡(jiǎn)單選擇器的話,都會(huì)執(zhí)行find函 數(shù),那我們?cè)倏纯磃ind到底是做用的:
復(fù)制代碼 代碼如下:
find: function( selector ) {
//在當(dāng)前的對(duì)象中查找
var elems = jQuery.map(this, function(elem){
return jQuery.find( selector, elem );
});
//下邊的代碼可以忽略,只是做一些處理
//這里應(yīng)用了js的正則對(duì)象的靜態(tài)方法test
//indexOf("..")需要了解一下xpath的語法,就是判斷selector中包含父節(jié)點(diǎn)的寫法
//本意就是過濾數(shù)組的重復(fù)元素
return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ?
jQuery.unique( elems ) :
elems );
}
如果這樣寫$(‘#id .className'),就會(huì)執(zhí)行到擴(kuò)展的find(‘#id .className',document),因?yàn)楫?dāng)前的this是document的jQuery數(shù)組,那我們?cè)诳纯磾U(kuò)展的find他的實(shí)現(xiàn),代碼比較 多,就不列出來,總之就是從第二個(gè)參數(shù)傳遞進(jìn)行的dom第一個(gè)子節(jié)點(diǎn)開始找,遇見#比對(duì)id,遇見.比對(duì)ClassName,還有:<+-等處理。 那我們要優(yōu)化,是不是就要想辦法讓第二個(gè)參數(shù)context的范圍最小,那樣遍歷是不是就很少了?
如果我們這樣寫$(‘#id').find(‘.className'),那程序只這樣執(zhí)行 的,第一次init的時(shí)候執(zhí)行一步getElementById,就return了,接著執(zhí)行 find(‘.className',divDocument),divDocument就是我們第一次選擇的是div標(biāo)簽,如果document下有很 多dom對(duì)象的時(shí)候,這次只遍歷divDocument是不是少了很多次,而且在第一次選擇id的速度也要比遍歷快的多。
現(xiàn)在大家應(yīng)該是明白了吧。就是說第一層選擇最好是ID,而是簡(jiǎn)單選擇器,目的就是定義范圍, 提高速度,這次就說這些,選擇寫法的優(yōu)化,其他的優(yōu)化,下次再說。
相關(guān)文章
jQuery實(shí)現(xiàn)鼠標(biāo)經(jīng)過時(shí)高亮,同時(shí)其他同級(jí)元素變暗的效果
這篇文章主要介紹了jQuery實(shí)現(xiàn)鼠標(biāo)經(jīng)過時(shí)高亮,同時(shí)其他同級(jí)元素變暗的效果,涉及jQuery基于事件響應(yīng)機(jī)制的頁面元素遍歷與屬性變換操作技巧,需要的朋友可以參考下2016-09-09jQuery EasyUI API 中文文檔 - DataGrid數(shù)據(jù)表格
jQuery EasyUI API 中文文檔 - DataGrid數(shù)據(jù)表格使用說明,需要的朋友可以參考下。2011-11-11Jquery.Form 異步提交表單的簡(jiǎn)單實(shí)例
這篇文章主要介紹了Jquery.Form 異步提交表單的簡(jiǎn)單實(shí)例。需要的朋友可以過來參考下,希望對(duì)大家有所幫助2014-03-03