平時(shí)工作中,相信很多小伙伴跟我一樣,jquery的index()方法用的很多,也用得很爽,一直都覺得不可思議。今天就偶然想了解一下它的實(shí)現(xiàn)原理,便翻起了jquery的源碼,窺得了它大致的實(shí)現(xiàn)原理。
場(chǎng)景重現(xiàn):(jquery自行引入)
html:
<ul id="test">
<li id="t1">1</li>
<li id="t2">2</li>
<li id="t3">3</li>
</ul>
js:
$("#test").on('click', 'li', function(e) {
console.log($(this).index());
})
就如此小的一個(gè)demo,引發(fā)了我對(duì)index()方法的種種聯(lián)想,為什么點(diǎn)擊當(dāng)前的元素可以知道它的索引呢?難道要預(yù)先知道它的父級(jí)嗎,這不可能,這些dom節(jié)點(diǎn)又不是固定的,那到底。。。。。。
下面就開啟源碼之旅吧。
首先是index()方法,其源碼如下:
index: function( elem ) {
// No argument, return index in parent
if ( !elem ) {
return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
}
// Index in selector
if ( typeof elem === "string" ) {
return indexOf.call( jQuery( elem ), this[ 0 ] );
}
// Locate the position of the desired element
return indexOf.call( this,
// If it receives a jQuery object, the first element is used
elem.jquery ? elem[ 0 ] : elem
);
}
源碼很精簡(jiǎn),而且我們只想看沒傳參時(shí)的index方法的用法,所以只看這句:
if ( !elem ) {
return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
}
其實(shí)這句的重點(diǎn)在prevAll方法,其它都是些使邏輯嚴(yán)謹(jǐn)?shù)拇a,因此我們側(cè)重點(diǎn)放在prevAll方法。所以,翻看了prevAll方法:
jQuery.each({
// ...此處省略了很多非相關(guān)代碼
prevAll: function( elem ) {
return dir( elem, "previousSibling" );
},
}, function(name, fn) { // ...省略 })
緊接著,我們看dir源碼:
function dir( elem, dir, until ) {
var matched = [],
truncate = until !== undefined;
while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
if ( elem.nodeType === 1 ) {
if ( truncate && jQuery( elem ).is( until ) ) {
break;
}
matched.push( elem );
}
}
return matched;
}
看到這里,其實(shí)大致思路已經(jīng)知道了:遍歷查找當(dāng)前元素的上一個(gè)同級(jí)元素,形成一個(gè)包含所有該元素的前面的元素的集合。可能有點(diǎn)拗口,回到我們的小demo,在控制臺(tái)模擬一下prevAll的過(guò)程,看著以下截圖應(yīng)該好理解些:

而dir函數(shù)已經(jīng)為我們過(guò)濾了文本節(jié)點(diǎn):
if ( elem.nodeType === 1 )
最終就是返回一個(gè)所有的前面元素的集合給我們了,然后index就是prevAll().length(該集合的長(zhǎng)度)了。
ps: 可能細(xì)心的小伙伴會(huì)發(fā)現(xiàn)有漏洞,index源碼上是這樣的:
if ( !elem ) {
return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
}
人家的prevAll明明沒傳參數(shù),那按道理prevAll就接收不到elem參數(shù),則elem為undefined,那就沒有后續(xù)的故事情節(jié)了。關(guān)于這個(gè),我只想說(shuō),你知道得太多了。。。。。。

由于本人精力有限,所以只能猜想是jQuery.each方法做了手腳,使得不傳參的prevAll里面的elem自動(dòng)變?yōu)閠his對(duì)象。(當(dāng)然這只是本人猜想),希望有知道的留言一下,共勉,謝謝大家。