如果selector是其他字串情況就比較多了比較複雜了
// 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裡面先判斷第一個字元是「<」最後一個字元是「>」且長度大於3就假設此時的selector是html簡單標籤,例如$('
init: function( selector, context, rootjQuery ) { var match, elem, ret, doc;
如果不滿足if的條件就會呼叫一個正規則去得到match的結果,quickExpr是jQuery建構函式裡面宣告的變數
// 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 )執行的結果可以是一個數組,數組的第一個元素是匹配的元素,剩下的分別是分組匹配的元素,這個正則有兩個分組(<[wW] > )[^>]和([w-]*)一個是標籤一個是id值。最終會把結果交給match。以下就來分析下match的各種情況首先單標籤不用正規式是 [ 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裡面我們建立一個jQuery物件然後再init方法裡面輸出得到的match結果:
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')然後再看一下結果
還有一個比較特殊的情況$(‘
我們可以看到id總是在第三個元素而標籤值在第二個元素保存著,對於最後一種情況而言跟$('
接下來的會根據match的結果分為三種情況
if ( match && (match[1] || !context) ) { ... } else if ( !context || context.jquery ) { ... } else { ... }
第一種情況滿足的條件是match一定要有值,match[1]就是第二個元素就是保存標籤的這個有值或不存在上下文,但是好像沒有id什麼事啊?其實不是的通過分析match的結果可以知道第二個元素沒有值肯定就是id選擇器得到的結果,而id是唯一的,不需要寫上下文(其實寫了上下文也會正常執行只不過會使用Sizzle而不是在這裡處理了跟body是一樣的)。好了第一個條件進來的狀況就是
1.標籤
$(‘
2.沒有上下文的id $(‘#div')
第一個條件內部又進行了細分:
// HANDLE: $(html) -> $(array) if ( match[1] ) { ... // HANDLE: $("#id") }else{ }
很顯然if是處理標籤的else是處理id的,先來看看是怎麼處理標籤的吧
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構造函數裡面宣告的目的是判斷單標籤 例如
然后把结果交给ret变量,基于ret的值又进行划分按照单标签和复杂标签分开处理ret值存在那就是匹配到了单标签然后再根据context是不是普通对象又分为两种情况isPlainObject是检测是不是普通对象的方法,如果是普通对象,就利用js原生方法createElement传入标签创建元素并放在一个数组里面,之所以这样是为了以后跟jquery对象合并方便,然后把数组赋值给selector,后采用对象冒充的方法调用attr方法,这里attr居然有3个参数,而平常我们使用的api里面是两个参数,其实jQuery中有很多类似的情况,同样的方法有着对内对外两个接口。第二个参数就是对象形式的上下文,因为attr可以像
这给我们的其实就是我们以后可以$(‘
不像之前的return this这里是返回merge执行后的结果其实他的任务就是把放在数组里面的创建好的的dom元素合并到jquery元素中去,最终变成{0:div,length:1...}这样的对象形式。这样的话简标签情况就处理完毕。
然后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;
很简单直接调用原生js的id选择器但是有一些系统会出现bug
注释说的很清楚黑莓系统,就是元素已经不存在了但是依然能够匹配得到所以再加上父节点,不存在的元素肯定没有父节点的。还有一种情况就是ie和opera浏览器会出现按name值匹配的情况所以在做了一个判断
if ( elem.id !== match[2] ) {
如果真的不幸出现了那就不能使用原生方法而是用find方法也就是使用sizzle引擎了,在大多数正常情况下就直接将获取到的元素放到this里面就可以啦然后修改下context的值。Ok终于把第一个大分支分析完了。然后再看根据match的第二个分支
else if ( !context || context.jquery ) { return ( context || rootjQuery ).find( selector ); }
这里是如果没有上下文或者上下文是jquery对象的时候这个比较简单就是直接用find方法了rootjQuery 就是$(document)
最后字符串的情况上面都不属于的话
This.constructor就是jQuery其实还是使用find方法。
以上所述就是本文的全部内容了,希望大家能够喜欢。