jQuery 的橫空出世,至今已有十個年頭了,而它的長盛不衰顯然不是沒有理由的。jQuery 提供了極為友好的接口,使得開發者們可以方便地進行 DOM 操作、發起 Ajax 請求、生成動畫……不一而足。此外,與 DOM API 不同的是,jQuery 采用了 “混合模式”。這意味著你可以在任何一個 jQuery 集合身上調用 jQuery 方法,而不用關心它到底包含了幾個元素(不管是零個、一個或多個,都沒問題)。
在未來的幾周內,jQuery 就將抵達一個重要的裡程碑——正式發布 3.0 版本。jQuery 3 修復了大量的 bug,增加了新的方法,同時移除了一些接口,並修改了少量接口的行為。在這篇文章中,我將為大家重點講解 jQuery 3 所引入的那些最重要的變化。
In the following sections I’ll discuss the most important features added in jQuery 3.
我們先來討論 jQuery 3 中最重要的幾個新增特性。
for...of
循環在 jQuery 3 中,我們可以用 for...of
循環語句來迭代一個 jQuery 集合中的所有 DOM 元素。這種新的迭代方法是 ECMAScript 2015(即 ES6)規范中的一部分。這個方法可以對 “可迭代對象”(比如 Array
、Map
、Set
等)進行循環。
當使用這種新的迭代方法時,你在循環體內每次拿到的值並不是一個 jQuery 對象,而是一個 DOM 元素(譯注:這一點跟 .each()
方法類似)。當你在對一個 jQuery 集合進行操作時,這個新的迭代方法可以少許改善你的代碼。
為了搞清楚這種迭代方法到底是怎麼工作的,我們來假設一個場景——你需要給頁面中的每個 input
元素分配一個 ID。在 jQuery 3 之前,你可能會這樣寫:
var $inputs = $('input'); for(var i = 0; i < $inputs.length; i++) { $inputs[i].id = 'input-' + i; }
In jQuery 3 you can write:
而在 jQuery 3 中,你就可以這樣寫了:
var $inputs = $('input'); var i = 0; for(var input of $inputs) { input.id = 'input-' + i++; }
(譯注:其實 jQuery 自己是有個 .each()
方法的,可讀性也不賴。)
$.get()
和 $.post()
函數的新簽名jQuery 3 為 $.get()
和 $.post()
這兩個工具函數增加了新簽名,從而使得它們和 $.ajax()
的接口風格保持一致。新簽名是這樣的:
$.get([settings]) $.post([settings])
settings
是一個對象,它包含多個屬性。它的格式和你以前傳給 $.ajax()
的參數格式是一樣的。如果你想更清楚地了解這個參數對象,請參考 $.ajax()
頁面 中的相關描述。
$.get()
和 $.post()
的參數對象與傳給 $.ajax()
的參數相比,唯一的區別就是前者的 method
屬性總是會被忽略。原因其實也很簡單,$.get()
和 $.post()
本身就已經預設了發起 Ajax 請求的 HTTP 方法了(顯然 $.get()
就是 GET,而 $.post()
就是 POST)。也就是說,正常人類應該是不會想用 $.get()
方法來發送一個 POST 請求的。
Consider the following code:
假設有以下一段代碼:
$.get({ url: 'https://www.audero.it', method: 'POST' // This property is ignored // 這個屬性將被忽略 });
Despite the method property, this statement won’t send a POST request but a GET request.
不管我們把 method
屬性寫成什麼,這個請求總是會以 GET 的方式發出去的。
requestAnimationFrame()
來實現動畫所有現代浏覽器(包括 IE10 及以上)都是支持 requestAnimationFrame
的。jQuery 3 將會在內部采用這個 API 來實現動畫,以便達到更流暢、更省資源的動畫效果。
unwrap()
方法jQuery 3 為 unwrap()
方法增加了一個可選的 selector 參數。這個方法的新簽名是這樣的:
unwrap([selector])
有了這個特性,你就可以給這個方法傳入一個包含選擇符表達式的字符串,用它來在父元素內進行匹配。如果存在匹配的子元素,則這個子元素的父層將被解除;如果沒有匹配,則不進行操作。
jQuery 3 還修改了一些特性的行為。
:visible
和 :hidden
jQuery 3 將會修改 :visible
和 :hidden
過濾器的含義。只要元素具有任何布局盒,哪怕寬高為零,也會被認為是 :visible
。舉個例子,br
元素和不包含內容的行內元素現在都會被 :visible
這個過濾器選中。
因此,如果你的頁面中包含如下的結構:
<div></div> <br />
然後運行以下語句:
console.log($('body :visible').length);
在 jQuery 1.x 和 2.x 中,你得到的結果會是 0
;但在 jQuery 3 中,你會得到 2
。
data()
方法另一個重要的變化是跟 data()
方法有關的。現在它的行為已經變得跟 Dataset API 規范 一致了。jQuery 3 將會把所有屬性鍵名轉換成駝峰形式。我們來詳細看一下,以如下元素為例:
<div id="container"></div>
當我們在用 jQuery 3 以前的版本時,如果運行如下代碼:
var $elem = $('#container'); $elem.data({ 'my-property': 'hello' }); console.log($elem.data());
將會在控制台得到如下結果:
{my-property: "hello"}
而在 jQuery 3 中,我們將會得到如下結果:
{myProperty: "hello"}
請注意,在 jQuery 3 中,屬性名已經變成了駝峰形式,橫槓已經被去除了;而在以前的版本中,屬性名會保持全小寫,並原樣保留橫槓。
Deferred
對象jQuery 3 還改變了 Deferred
對象的行為。Deferred
對象可以說是 Promise
對象的前身之一,它實現了對 Promise/A+ 協議 的兼容。這個對象以及它的歷史都相當有意思。如果想要深入了解,你可以去閱讀 jQuery 官方文檔,也可以去看我寫的書《jQuery 實戰(第三版)》——這本書也涵蓋了 jQuery 3。
在 jQuery 1.x 和 2.x 中,傳給 Deferred
的回調函數內如果出現未捕獲的異常,會立即中斷程序的執行(譯注:即靜默失敗,其實 jQuery 絕大多數回調函數的行為都是這樣的)。而原生的 Promise
對象並非如此,它會拋出異常,並不斷向上冒泡,直至到達 window.onerror
(通常冒泡的終點是這裡)。如果你沒有定義一個函數來處理這個錯誤事件的話(通常我們都不會這麼做),那這個異常的信息將會被顯示出來,此時程序的執行才會停止。
jQuery 3 將會遵循原生 Promise
對象的模式。因此,回調內產生的異常將會導致失敗狀態(rejection),並觸發失敗回調。一旦失敗回調執行完畢,整個進程就將繼續推進,後續的成功回調將被執行。
為了讓你更好地理解這個差異,讓我們來看一個小例子。比如我們有如下代碼:
var deferred = $.Deferred(); deferred .then(function() { throw new Error('An error'); }) .then( function() { console.log('Success 1'); }, function() { console.log('Failure 1'); } ) .then( function() { console.log('Success 2'); }, function() { console.log('Failure 2'); } ); deferred.resolve();
在 jQuery 1.x 和 2.x 中,只有第一個函數(也就是拋出錯誤的那個函數)會被執行到。此外,由於我們沒有為 window.onerror
定義任何事件處理函數,控制台將會輸出 “Uncaught Error: An error”,而且程序的執行將中止。
而在 jQuery 3 中,整個行為是完全不同的。你將在控制台中看到 “Failure 1” 和 “Success 2” 兩條消息。那個異常將會被第一個失敗回調處理,並且,一旦異常得到處理,那麼後續的成功回調將被調用。
沒有哪一個 jQuery 版本(包括 jQuery 3)曾官方宣稱支持 SVG 文檔。不過事實上有很多方法是可以奏效的,此外還有一些方法在以前是不行的(比如操作類名的那些方法),但它們在 jQuery 3 中也得到了更新。因此,在 jQuery 3 中,你應該可以放心使用諸如 addClass()
和 hasClass()
這樣的方法來操作 SVG 文檔了。
在增加了上述改進的同時,jQuery 也移除、廢棄了一些特性。
bind()
、unbind()
、delegate()
和 undelegate()
方法jQuery 在很久以前就引入了 on()
方法,它提供了一個統一的接口,用以取代 bind()
、delegate()
和 live()
等方法。與此同時,jQuery 還引入了 off()
這個方法來取代 unbind()
、undelegated()
和 die()
等方法。從那時起,bind()
、delegate()
、unbind()
和 undelegate()
就已經不再推薦使用了,但它們還是一直存在著。
jQuery 3 終於開始將這些方法標記為 “廢棄” 了,並計劃在未來的某個版本(很可能是 jQuery 4)中將它們徹底移除。因此,請在你的項目中統一使用 on()
和 off()
方法,這樣你就不用擔心未來版本的變更了。
load()
、unload()
和 error()
方法jQuery 3 徹底拋棄了 load()
、unload()
和 error()
等已經標記為廢棄的方法。這些方法在很早以前(從 jQuery 1.8 開始)就已經被標記為廢棄了,但一直沒有去掉。如果你正在使用的某款插件仍然依賴這些方法,那麼升級到 jQuery 3 會把你的代碼搞掛。因此,在升級過程中請務必留意。
context
、support
和 selector
屬性jQuery 3 徹底拋棄了 context
、support
和 selector
等已經標記為廢棄的屬性。同上,在升級到 jQuery 3 時,請留意你正使用的插件。
jQuery 3 修復了以往版本中的一些非常重要的 bug。在本節中,我將著重介紹其中兩處,因為這兩者應該會對你寫代碼的習慣帶來顯著影響。
width()
和 height()
的返回值將不再取整jQuery 3 修復了 width()
、height()
和其它相關方法的一個 bug。這些方法的返回值將不再捨入取整,因為這種取整行為在某些情況下不便於對元素進行定位。
我們來詳細看一看。假設你一個寬度為 100px
的容器元素,它包含了三個子元素,寬度均為三分之一(即 33.333333%):
<div class="container"> <div>My name</div> <div>is</div> <div>Aurelio De Rosa</div> </div>
在 jQuery 3 以前的版本中,如果你嘗試通過以下代碼來獲取子元素的寬度……
$('.container div').width();
……那麼你得到結果將是 33
。原因在於 jQuery 會把 33.33333 這個值取整。而在 jQuery 3 中,這個 bug 已經被修復了,因此你將會得到更加精確的結果(即一個浮點數)。
wrapAll()
方法jQuery 3 還修復了 wrapAll()
方法中的一個 bug,這個 bug 出現在把一個函數作為參數傳給它的情況下。在 jQuery 3 以前的版本中,當一個函數被傳給 wrapAll()
方法時,它會把 jQuery 集合中的每個元素單獨包裹起來。換句話說,這種行為和把一個函數傳給 wrap()
時的行為是完全一樣的。
在修復這個問題的同時,還引入了另外一個變更:由於在 jQuery 3 中,這個函數只會調用一次了,那就無法把 jQuery 集合中每個元素都傳給它。因此,這個函數的執行上下文(this
)將只能指向當前 jQuery 集合中的第一個元素。
If this article was of any interest to you, you might want to try the first beta of jQuery 3. You can obtain it by accessing one of the two URLs below.
既然你已經讀到了這裡,那說明你很可能想試試 jQuery 3 的第一個 beta 測試版。你可以通過以下兩個地址來獲取這個版本:
It’s also available on npm and you can download it by running the command:
當然,你還可以通過 npm 來下載:
npm install [email protected]
Many people state that jQuery is dead and it doesn’t have a place in modern web development anymore. However, its development continues and statistics of its adoption (78.5% in the top million) contradict these claims.
很多人一直在唱衰 jQuery,說它在現代網頁開發中已經沒有一席之地了。但不管怎樣,jQuery 的開發仍在繼續,客觀的統計數據(在排名前一百萬名的網站中占有率高達 78.5%)也讓這些論調不攻自破。
In this article, I’ve walked you through the main changes that jQuery 3 will feature. As you might have noticed, this version is unlikely to break any of your existing projects as it doesn’t introduce many breaking changes. Nonetheless, there are some points to keep in mind when upgrading such as the improvement of the Deferred
object. As is always the case before update a third-party dependency, a review of the project will help you spot any unexpected behavior or broken functionality.
在本文中,我已經帶你了解了一遍 jQuery 3 將會帶來的一些重大變化。或許你已經察覺到了,這個版本並不太可能搞掛你的既有項目,因為它引入的破壞性變更其實寥寥無幾。不過,在升級到 jQuery 3 的過程中,你還是有必要牢記一些關鍵點,比如 Deferred
對象的改進等等。同樣,在升級某個第三方庫時,也有必要檢查一下該項目的兼容性情況,以便盡早發現任何非預期行為,避免某些功能失效。
除了本文所提及的變更之外,jQuery 3.0 最大的變化就是徹底放棄對 IE8 的支持。jQuery 團隊做出這個決定的原因在於,微軟已經在今年年初宣布停止對 IE 8~10 的支持。因此,jQuery 在 3.0 alpha 階段所發布的 jQuery Compat 項目也就沒有繼續存在的必要了。
不過,由於 IE8 仍然是中國大陸最流行的浏覽器之一,對國內的開發者來說,在短期(甚至中期)內還不得不停留在 jQuery 1.x 版本。
好吧,最後還是說個好消息吧。為幫助用戶平滑升級,此次 jQuery 同樣會為 3.0 版本提供遷移插件(jQuery Migrate plugin)。在把 jQuery 升級到 3.0 之後同時運行這個插件,即可確保基於 jQuery 1.x 或 2.x 的既有業務代碼正常運行;同時,它還將在控制台向你報告既有代碼與 jQuery 3 不兼容的地方。當你修復了這些不兼容問題之後,就可以安全地移除這個插件了。
jQuery權威指南 PDF版中文+配套源代碼 http://www.linuxidc.com/Linux/2013-10/91059.htm
jQuery實戰 中文PDF+源碼 http://www.linuxidc.com/Linux/2013-09/90631.htm
《jQuery即學即用(雙色)》 PDF+源代碼 http://www.linuxidc.com/Linux/2013-09/90383.htm
鋒利的jQuery(第2版) 完整版PDF+源碼 http://www.linuxidc.com/Linux/2013-10/91527.htm
jQuery完成帶復選框的表格行高亮顯示 http://www.linuxidc.com/Linux/2013-08/89406.htm
jQuery基礎教程(第4版) PDF 完整高清版+配套源碼 http://www.linuxidc.com/Linux/2014-03/98162.htm
--------------------------------------分割線 --------------------------------------
jQuery 的詳細介紹:請點這裡
jQuery 的下載地址:請點這裡