標籤:
在這部分中,主要是添加一些JQ的方法和屬性,如:
JQuery:2.0.3 JQ版本
constructor:JQuery 重新指向JQ建構函式
init(): 初始化和參數管理的方法。
selector:儲存選擇字串
length:this對象的長度
toArray():轉換數組的方法
未完
代碼解析:
這部分的代碼都包含在
jQuery.fn = jQuery.prototype = {};
首先是對JQ版本的賦值和重指向:
jquery: core_version,constructor: jQuery,
這裡需要住的是重指向,看如下代碼:
function Obj() { } Obj.prototype.age = 10; var o1 = new Obj(); console.log(o1.constructor); //function Obj(){} function ObjNew() { } ObjNew.prototype = { age:10 } var o1New = new ObjNew(); console.log(o1New.constructor); //function Object(){}
運行代碼可以看到,第二種通過字面量賦值的方式,對象上的constructor會丟失。因為這種方式是將原型上的對象進行覆蓋操作,而不是添加。所以在JQ源碼中需要重新指定一下。
INIT方法:
init方法是JQ最先執行的方法,通過這段代碼進行調用:
jQuery = function( selector, context ) { // The jQuery object is actually just the init constructor ‘enhanced‘ return new jQuery.fn.init( selector, context, rootjQuery ); },
init方法會接收三個參數,分別是:
selector:$()括弧中的第一個參數。如:"#id" ".class" "<li>" document function()等
context:執行的上下文
rootJquery:JQ的根對象。
然後定義變數,並檢查selector是否為空白也就是對 $(""),$(null),$(undefind),$(false) 進判斷。
var match, elem;// HANDLE: $(""), $(null), $(undefined), $(false)if ( !selector ) { return this;}
通過校正之後,接著是判斷selector的類型:
if ( typeof selector === "string" ) { //實現代碼} else if ( selector.nodeType ) { //實現代碼} else if ( jQuery.isFunction( selector ) ) { //實現代碼}
依次對字串、節點、函數進行判斷,並分別進行了單獨的處理
先對字串中的代碼進行解析:
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 = rquickExpr.exec( selector ); }
首先對字串進行判斷,如果傳入的selector是"<li>"或"<li>1</li><li>2</li>"這種形式想要建立節點的,則 match=[null,"<li>",null]或則 match=[null,"<li>1</li><li>2</li>",null]
否則進行正則匹配,例如:$("#id"),$(".class"),$("div") 這種形式的。
match=null;//$(".class") $("div") $("#div div.class")
match=["#id",null,"id"] //$("#id")
match=["<li>hello","<li>",null] //$("<li>hello")
這裡先對JQ的內部執行有一個說明,例如:$("li").css("background","red") 這段代碼,對頁面上的所有li的背景顏色賦值。那麼這句代碼的兩部分分別做了什麼處理呢。
首先 $("li") 其實是選擇了頁面上所有的li,並返回了一個this對象存放這些li的節點,
然後通過這個對象在對.css方法進行調用,在css方法內部的實作類別似於:
for(var i=0;i<this.length;i++){ this[i].style.background="red";}
瞭解完這個過程在看下面的代碼:
if ( match && (match[1] || !context) ) {
}
這個判斷首先判斷math不為null,並且match[1]有值,那麼這就代表建立標籤的語句滿足條件,或者context為空白,context為空白代表是選擇id,因為id沒有上下文,所以滿足這個條件的有:
$("<li>"),$("#id")
接下來在條件裡進一步判斷:
if ( match && (match[1] || !context) ) { // HANDLE: $(html) -> $(array) if ( match[1] ) { //判斷是建立標籤還是id } else { //id執行這 }
在這個條件裡又將建立標籤和尋找id區分。
先看建立標籤的源碼:
context = context instanceof jQuery ? context[0] : context; // scripts is true for back-compat jQuery.merge( this, jQuery.parseHTML( match[1], context && context.nodeType ? context.ownerDocument || context : document, true ) );
這段代碼中,先將context賦值,在建立標籤時,有是可能需要第二參數,這個第二個參數也就是執行內容,例如:$("<li>",document) 一般很少這樣使用,但是當頁面中有iframe時,想在iframe中建立,那麼第二參數設定為iframe後,就在iframe中建立了。
context instanceof jQuery ? context[0] : context 這句目的就是將context賦值為原生的節點,當我傳遞參數時,可能會:
1、$("<li>",document)
2、$("<li>",$(document))
這兩種形式,同過這判斷是否用第二種形式傳入,如果是,則將原生的document對象賦值。
然後用到兩個方法:jQuery.merge和jQuery.parseHTML方法。
先說一下jQuery.parseHTML方法,代碼如下:
var str = "<li>1</li><li>2</li><li>3</li><li>4</li><li>5</li>"; var arr = jQuery.parseHTML(str, document, true); console.log(arr);
執行結果為,
可以看到這個方法是將字串轉換為數組的形式。需要特別注意的最後一個參數,預設為false,為false代表不可以插入script代碼,為true則代表可以。
再看下jQuery.merge方法
這個方法常用的功能就是將兩個數組合并,如:
var arry1 = ["a", "b"]; var arry2 = ["c", "d"]; var arry3 = jQuery.merge(arry1, arry2); console.log(arry3); //["a", "b", "c", "d"]
但這裡的this對象是個json對象,通過他也可以進行合并。並返回jq想要的json格式。如:
var arry1 = { 0: "a", 1: "b", length:2 }; var arry2 = ["c", "d"]; var arry3 = jQuery.merge(arry1, arry2); console.log(arry3);
結果如下:
接下來處理特殊的形式,也是很少使用的一種建立標籤的方式,代碼如下:
if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { for ( match in context ) { // Properties of context are called as methods if possible if ( jQuery.isFunction( this[ match ] ) ) { this[ match ]( context[ match ] ); // ...and otherwise set as attributes } else { this.attr( match, context[ match ] ); } } }
這種匹配的是:$("<li>",{title:"hello",html:"aaaaaaa"}) 後面有個json對象當參數的方式。
如果是這種方式的話,那麼會迴圈這個json對象,先判斷json裡的屬性是否是jq內建的方法,如果是,則直接調用方法,否則,進去else,用jq的attr方法為這個標籤加一個屬性。
到這裡建立標籤的方式就介紹完了。下面介紹一下傳入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 ) { // Inject the element directly into the jQuery object this.length = 1; this[0] = elem; } this.context = document; this.selector = selector; return this;
代碼很簡單,但需要注意一下判斷,這是為了最黑莓瀏覽器的相容,因為在黑莓4.6版本的瀏覽器中,當刪除節點之後,還可以用js代碼尋找到這個節點,
所以需要進行一下父節點的判斷,因為任何節點都會有父節點。
接下來也是返回一個JQ需要的特殊json格式。賦值長度為1,第一個對象是當前尋找到的對象。然後把上下文賦值document,賦值selector。
到這裡已經把建立標籤和id尋找的源碼分析完了,其他複雜尋找的代碼會進入下面的代碼:
} else if ( !context || context.jquery ) { return ( context || rootjQuery ).find( selector ); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return this.constructor( context ).find( selector ); }
這段代碼的判斷就是要保證$("ul",document).find("li") $("ul",$(document)).find("li") 這兩種形式,都會執行:jQuery(document).find();這個方法。
到這就把當參數是字串傳入時,要執行的代碼解析完了,下面分析傳入節點或者方法時要執行的代碼。
JQuery源碼解析-添加JQuery的一些方法和屬性