jQuery對象是使用構造函數和原型模式相結合的方式建立的。如今來看看jQuery的原型對象jQuery.prototype:jquery
1 jQuery.fn = jQuery.prototype = { 2 //成員變量和方法 3 }
這裏給原型對象起了一個別名叫作jQuery.fn。要注意的是這個jQuery.fn可不是jQuery對象的屬性,而是jQuery構造方法自己的屬性,它是不會傳給它所建立的對象的。若是你在控制檯敲$().fn的話輸出的結果會是undefined。接下來看看原型對象裏面有些什麼:chrome
1 jquery: "2.1.1", 2 3 constructor: jQuery,
jquery:在原型對象中,先定義了jquery屬性來標識版本信息,這裏是2.1.1版。在咱們寫代碼的時候能夠經過查看這個屬性判斷對象是否是jQuery對象。數組
constructor:這個屬性在低版本的jQuery代碼中是沒有的(例如遠古的1.2.6版本)。在這裏我能看見這個屬性我真的以爲如今的jQuery成熟了。每個對象都有一個constructor屬性,是由建立它的構造函數的原型對象傳遞而來,指向了建立它的構造方法。也就是若是你在chrome的控制檯敲:dom
1 var obj = {}; 2 3 obj.constructor;
控制檯會顯示:函數
function Object() { [native code] }學習
構造函數的原型是在定義構造函數的時候自動生成,其中的constructor會自動指向該構造函數。也就是你在輸入:ui
1 function Obj(){} 2 3 Obj.prototype.constructor
控制檯會輸出: this
function Obj(){}spa
如今回過頭咱們再來看看jQuery的代碼。定義jQuery.prototype時:prototype
1 jQuery.fn = jQuery.prototype = { 2 //成員變量和方法 3 }
這裏的過程實際上是新建一個對象,而後將jQuery.prototype指向這個新建的對象。而這時新建對象由於是由function Object(){}方法構建的。因此它的constructor屬性實際上是指向的function Object(){}方法。進而致使全部由jQuery方法建立的對象的constructor也是指向的
function Object(){}方法。這裏從新定義jQuery.prototype.constructor屬性,讓它從新指向jQuery構造函數。日常咱們在使用jQuery的時候也許永遠也不會用到constructor這個屬性,可是這種小細節的完善無疑讓整個代碼變得嚴謹不少。
繼續往下看代碼:
1 // Start with an empty selector 2 selector: "", 3 4 // The default length of a jQuery object is 0 5 length: 0,
selector:這個屬性指的是默認的選擇器。
length:jQuery對象實際上是一個類數組對象。什麼叫類數組對象?個人理解是它不是一個數組,而是一個對象可是當咱們訪問它的數據時某些表現形式跟數組很類似,好比能夠用[0]、[1]....[n]來訪問數據,能夠用length來獲取數據的數目。jQuery就是一種類數組對象經過選擇器選擇頁面dom元素,並以jq[0]、jq[1]、jq[2]...、jq[n]的形式將個元素存儲在jQuery對象中,這個length屬性就是用來記錄元素個數。
繼續往下:
1 var arr = []; 2 3 var slice = arr.slice; 4 5 toArray: function() { 6 return slice.call(this); 7 },
toArray:這個方法是將jQuery對象轉化爲一個數組(是真正的數組哦)。咱們知道數組的
slice(start,end)
方法可從已有的數組中返回選定的元素而不破壞原有的數組,當參數不填的時候就返回這個數組的一個副本。由於jQuery對象是類數組對象,因此這裏直接將數組arr中slice的對象上下文換成當前jQuery對象(不知道這個對象上下文能不能理解成做用域哈,不過this確定是指的新對象啦)。slice函數執行後返回一個真正的js數組,裏面的元素就是jQuery對象中的各個dom元素,可是又不破壞原來的jQuery對象,這一招真的挺不錯,一行代碼使用現有的資源解決了不少事情,這種思路要多學習。不過slice的調用咱們還能夠用
Array.prototype.slice.call(this)
這種方式調用也是能夠的,不用特地新建一個對象。
往下:
1 get: function(num) { 2 return num != null ? 3 4 // Return just the one element from the set 5 (num < 0 ? this[num + this.length] : this[num]) : 6 7 // Return all the elements in a clean array 8 slice.call(this); 9 },
get:這個方法感受根據傳參不一樣會有兩個功能。一個是若是傳參num不爲空的話,那麼根據num返回jQuery對象中的相應dom元素。另外一個就是當num爲空得時候將jQuery對象轉換爲數組。因此我一直很奇怪爲啥有了get方法還要專門寫一個toArray方法,但願有大大爲我解惑。
我們繼續:
1 pushStack: function(elems) { 2 3 // Build a new jQuery matched element set 4 //jQuery.merge:合併兩個數組的內容到第一個數組中 5 var ret = jQuery.merge(this.constructor(), elems); 6 7 // Add the old object onto the stack (as a reference) 8 ret.prevObject = this; 9 ret.context = this.context; 10 11 // Return the newly-formed element set 12 return ret; 13 },
pushStack:你們都知道當咱們使用jQuery選擇區建立jQuery對象後,例如$(".class"),還可使用jq.find、jq.filter等方法進一步處理,返回新的jQuery對象。可是這樣每每會對舊的jQuery產生「破壞」性德影響,由於它們會修改匹配元素的集合(在jQuery中被稱爲matched element set)因此jQuery在進行這種「破壞性」的操做以前就會調用pushStack方法將現有的匹配元素集合暫時保存起來。
首先調用jQuery.merge方法,它將兩個數組合併到第一個數組中。不過我以爲頗有意思的是兩個傳參:
第一個參數this.constructor指的是jQuery構造方法原型對象中的constructor屬性,這個前面說過。的this.constructor()指的是調用jQuery構造方法構建一個新對象,如同$()同樣。由於jQuery是類數組對象因此也能夠充當merge的傳參。我以爲很炫酷的是這裏建立新jQuery的寫法,要是我本人的話我確定會直接用jQuery()這麼寫了。
第二個參數elems就是pushStack傳進來的參數了,它能夠是真正的數組,也能夠是類數組對象。經過merge方法,能夠將elems轉化爲一個jQuery對象。
接下來就很簡單了,將當前對象用ret.prevObject保存起來,值得一提的是這裏還專門用了一個ret.context來保存當前jQuery對象的選擇器上下文,就是使用選擇器匹配元素時第二個參數,eg:$("div",document.getElementById("id"))。我查了一下w3c.school,context 屬性在 jQuery version 1.10 中被棄用,可是高版本的jQuery中還能看到這個,因此我也不知道到底怎麼回事。
不過既然說到jQuery.merge了那乾脆來看看它吧:
1 merge: function(first, second) { 2 var len = +second.length, 3 j = 0, 4 i = first.length; 5 6 for (; j < len; j++) { 7 first[i++] = second[j]; 8 } 9 10 first.length = i; 11 12 return first; 13 },
具體代碼就不細說了~~~沒什麼技術含量,值得一提的是從merge的代碼上看好像並無去重的功能。這裏的去重不只僅是重複數字什麼的,更包含重複的元素。比方說:
1 var arr1 = [], arr2 = []; 2 3 var ele = document.getElementById("id"); 4 5 arr1.push(ele); 6 arr2.push(ele); 7 8 var arr3 = jQuery.merge(arr1, arr2);
運行後arr3.length將會是2雖然兩個元素實際上是同一個dom對象的引用。