jQuery是時下最為流行的JavaScript庫。它使用CSS選擇器樣式語法獲取文檔對象模型(DOM)中的元素到已包裝的對象集合中,然后使用jQuery方法操縱這些元素來達(dá)到不同的效果。盡管jQuery的使用是非常方便和直觀的,我們還是需要弄懂它背后的機(jī)制來更好的掌握它。
jQuery中的基本概念
在我們深入研究jQuery庫前,需要了解一些jQuery中的一些基本概念。
$/jQuery對象和$()/jQuery()方法
$/jQuery對象是一個全局對象,通過它來訪問所有的jQuery方法。
它也是一個方法對象,所以使用它最通常的方法是通過$/jQuery()方法。$/jQuery()方法可以用來選擇DOM中的一組元素。它也是一個包裝函數(shù),一個$/jQuery()方法的簡單例子:
傳給$/jQuery()方法的參數(shù)是選擇器( selector)。選擇器是一個有CSS選擇器樣式語法的表達(dá)式。在上面的例子中,我要選擇id等于 #ABC 的元素
包裝集合(Wrapped set)
包裝集合是一個類似數(shù)組的結(jié)構(gòu),里面包含了所有已選擇的DOM元素。上面的$("#ABC")返回了一個包裝集合。你可以像遍歷數(shù)組那樣訪問包裝集合或者通過索引訪問。更重要的是,你可以在所有被選擇的元素上應(yīng)用jQuery方法。
jQuery $()/jQuery()方法在后臺是怎么工作的
因?yàn)榇蠖鄶?shù)jQuery方法調(diào)用都是以$()/jQuery()開頭的,所以我們有必要弄懂在這后面發(fā)生了什么。在深入討論前,我們先看看$()/jQuery()對象是在哪定義的。$/jQuery對象是jQuery方法的訪問點(diǎn),是在jQuery中定義的一個全局方法變量。這是在jQuery源碼中定義它的那一行:
2 | window.jQuery = window.$ = jQuery; |
window對象代表瀏覽器中打開的窗口,把$/jQuery放到window下,它就得定義為一個全局對象并且可以在當(dāng)前打開的窗口中訪問
但是,上面一行源碼最的"jQuery"是什么?它被聲明在jQuery庫開始的地方。
1 | var jQuery = ( function () { |
這所有的魔法都發(fā)生在jQuery對象的聲明表達(dá)式中,如果你直接往里面看,可能會迷茫,所以讓我來簡化它吧。
簡化版jQuery庫源代碼
警告:簡化版本僅僅為了研究目的,它不并具有jQuery提供的所有功能,不要把它用在真實(shí)環(huán)境中。
01 | var jQuery = ( function () |
04 | var k = function (selector, context) |
07 | var kobj = new k.fn.init(selector, context); |
12 | k.fn = k.prototype = { |
13 | init: function (selector, context) |
23 | k.fn.init.prototype = k.fn; |
從上面的額源碼你可以看到j(luò)Query函數(shù)變量被定義為一個匿名方法的執(zhí)行結(jié)果。
小貼士:怎樣定義匿名函數(shù) 在Javascript中你可以定義一個匿名函數(shù)并馬上調(diào)用它 例如, (function () { alert(“hello world”); })(); 通過把函數(shù)表達(dá)式 function() { alert(“hello word”); } 放進(jìn)括號中 (function() { alert(“hello world”); }) 你可以在外面再加個括號馬上調(diào)用它
在這個匿名函數(shù)內(nèi)部定義了一個函數(shù),它有這樣的形式:
1 | function (selector, context) |
第一個參數(shù)是selector,第二個參數(shù)是context。在原始的jQuery源碼中,函數(shù)k實(shí)際上被命名為jQuery,這會和外面大多數(shù)jQuery函數(shù)變量混淆。
在函數(shù)k內(nèi)一個匿名函數(shù)類定義為k的prototype,Prototype是JavaScript函數(shù)類的一個特殊的,被用來指向另一個函數(shù)對象。所以,所有那個函數(shù)類的實(shí)例都可以訪問在prototype函數(shù)類中定義的函數(shù)。在這里,init函數(shù)可以被函數(shù)類k的所有實(shí)例訪問。init方法有如下的形式:
1 | function (selector, context) |
k的prototype里已經(jīng)初始化成員方法,與此同時,init函數(shù)的prototype又被賦值為k的prototype。這是一個循環(huán)引用,正常編程實(shí)踐中應(yīng)該避免。但是,jQuery就是采用這種方式使init函數(shù)的返回值可以訪問k中定義的方法。
小貼士:在JavaScript中函數(shù)是實(shí)體類 Javascript是函數(shù)式編程語言,但是函數(shù)并不是傳統(tǒng)中那樣純粹的函數(shù)。函數(shù)可以動態(tài)定義,可以擁有屬性和方法,并且可以作為參數(shù)傳遞給另一個函數(shù)。如果你想以傳統(tǒng)的方式執(zhí)行函數(shù),可以這樣: function display() { alert(“hello world”); } display(); 如果你想把函數(shù)當(dāng)做類使用,可以這樣: function Car(model) { this.Model = model; this.Drive = function() { alert(“Go”) } } var car = new Car(“Ford”); 在這里,function實(shí)際上是用來定義一個Car“類”,Car類有一個可以用函數(shù)類的參數(shù)初始化的屬性Model和方Drive方法。所以,你可以隨便創(chuàng)建任意多個Car類的對象。然而,JavaScript的類并不是真正的類,因?yàn)樗]有面向?qū)ο笳Z言中類的三個主要特征。
定義k的prototype函數(shù)的方法被稱作function literal,這在jQuery中廣泛使用。
小貼士:JavaScript中定義方法的各種方式 1.使用function statement: function open() { //open logic } 2.使用function literal你可以用下面的方式定義最簡單的函數(shù): var o = { } 你還可以用literal定義一個函數(shù)“類”: var apple = { type: “macintosh”, color: “red”, getInfo: function() { return this.color + ‘ ‘ + this.type + ‘ apple’; } } 3.使用Function對象定義函數(shù) Function對象是JavaScript中內(nèi)建的對象,在JavaScript中,可以這樣 var add = new Function(a, b, “return a + b;”); 來定義一個函數(shù)“add”。Function會把開始的兩個參數(shù)“a”和"b"當(dāng)做函數(shù)的參數(shù),最后一個參數(shù)“return a + b”當(dāng)做函數(shù)體。
這樣,內(nèi)部的函數(shù)k就返回給了外部變量jQuery。jQuery得到的不僅是函數(shù)k,而且還有函數(shù)k所在的閉包(closure)。
小貼士:JavaScript中的closure是什么? closure是把內(nèi)部函數(shù)返回到外部時JavaScript創(chuàng)建的一個上下文(context),所以內(nèi)部的函數(shù)還是可以訪問那些本地變量。 closure的一個例子: var addition = function(numberA) { return function(numberB) { alert (numberA + numberB); }} 這樣,你就可以直接指定numberA的值來創(chuàng)建一個addition的實(shí)例。 var add2 = addition(2); var add3 = addition(3); add2(3); // it will display 5 add3(3); // it will display 6
最后,函數(shù)k被返回到了全局jQuery函數(shù)那里。
jQuery函數(shù)庫錯綜復(fù)雜的設(shè)計是為了使擴(kuò)展和使用這個庫簡單容易。你可以附加自定義函數(shù)到j(luò)Query.fn來添加你自己的業(yè)務(wù)邏輯。這個自定義的函數(shù)可以像內(nèi)置函數(shù)那樣被調(diào)用,比如:
2 | jQuery.fn.Test = function () { alert( "Test" ); } |
總結(jié)
通過了解jQuery是如何工作的,我們可以更好地掌握這個JavaScript庫。 我在這篇文章中顯示的僅僅是jQuery庫的框架。在掌握了基本的設(shè)計原則和jQuery庫機(jī)制后,你可以深入研究jQuery庫的原始源代碼來更多的了解jQuery如何發(fā)揮JavaScript語言的優(yōu)勢,實(shí)現(xiàn)簡單和可擴(kuò)展性的目標(biāo)。