新增特性
我們先來討論 jQuery 3 中最重要的幾個新增特性。
for...of
迴圈
for...of
迴圈在 jQuery 3 中,我們可以用 for...of
迴圈語句來迭代一個 jQuery 集合中的所有 DOM 元素。這種新的迭代方法是 ECMAScript 2015(即 ES6)規範中的一部分。這個方法可以對 “可迭代物件”(比如 Array
、Map
、Set
等)進行迴圈。
當使用這種新的迭代方法時,你在迴圈體內每次拿到的值並不是一個 jQuery 物件,而是一個 DOM 元素(譯註:這一點跟 .each()
方法類似)。當你在對一個 jQuery 集合進行操作時,這個新的迭代方法可以少許改善你的程式碼。
為了搞清楚這種迭代方法到底是怎麼工作的,我們來假設一個場景——你需要給頁面中的每個 input
元素分配一個 ID。在 jQuery 3 之前,你可能會這樣寫:
1 2 3 4 5 |
var $inputs = $('input'); for(var i = 0; i $inputs.length; i++) { $inputs[i].id = 'input-' + i; } |
而在 jQuery 3 中,你就可以這樣寫了:
1 2 3 4 5 6 |
var $inputs = $('input'); var i = 0; for(var input of $inputs) { input.id = 'input-' + i++; } |
(譯註:其實 jQuery 自己是有個 .each()
方法的,可讀性也不賴。)
$.get()
和 $.post()
函式的新簽名
jQuery 3 為 $.get()
和 $.post()
這兩個工具函式增加了新簽名,從而使得它們和 $.ajax()
的介面風格保持一致。新簽名是這樣的:
1 2 3 |
$.get([settings]) $.post([settings]) |
settings
是一個物件,它包含多個屬性。它的格式和你以前傳給 $.ajax()
的引數格式是一樣的。如果你想更清楚地瞭解這個引數物件,請參考 $.ajax()
頁面 中的相關描述。
$.get()
和 $.post()
的引數物件與傳給 $.ajax()
的引數相比,唯一的區別就是前者的 method
屬性總是會被忽略。原因其實也很簡單,$.get()
和 $.post()
本身就已經預設了發起 Ajax 請求的 HTTP 方法了(顯然 $.get()
就是 GET,而 $.post()
就是 POST)。也就是說,正常人類應該是不會想用 $.get()
方法來傳送一個 POST 請求的。
假設有以下一段程式碼:
1 2 3 4 5 |
$.get({ url: 'https://www.audero.it', method: 'POST' // This property is ignored // 這個屬性將被忽略 }); |
不管我們把 method
屬性寫成什麼,這個請求總是會以 GET 的方式發出去的。
採用 requestAnimationFrame()
來實現動畫
所有現代瀏覽器(包括 IE10 及以上)都是支援 requestAnimationFrame
的。jQuery 3 將會在內部採用這個 API 來實現動畫,以便達到更流暢、更省資源的動畫效果。
unwrap()
方法
unwrap()
方法jQuery 3 為 unwrap()
方法增加了一個可選的 selector 引數。這個方法的新簽名是這樣的:
1 |
unwrap([selector]) |
有了這個特性,你就可以給這個方法傳入一個包含選擇符表示式的字串,用它來在父元素內進行匹配。如果存在匹配的子元素,則這個子元素的父層將被解除;如果沒有匹配,則不進行操作。
有變更的特性
jQuery 3 還修改了一些特性的行為。
:visible
和 :hidden
:visible
和 :hidden
jQuery 3 將會修改 :visible
和 :hidden
過濾器的含義。只要元素具有任何佈局盒,哪怕寬高為零,也會被認為是 :visible
。舉個例子,br
元素和不包含內容的行內元素現在都會被 :visible
這個過濾器選中。
因此,如果你的頁面中包含如下的結構:
1 2 |
<div><div> <br /> |
然後執行以下語句:
1 |
console.log($('body :visible').length); |
在 jQuery 1.x 和 2.x 中,你得到的結果會是 0
;但在 jQuery 3 中,你會得到 2
。
data()
方法
data()
方法另一個重要的變化是跟 data()
方法有關的。現在它的行為已經變得跟 Dataset API 規範 一致了。jQuery 3 將會把所有屬性鍵名轉換成駝峰形式。我們來詳細看一下,以如下元素為例:
1 |
<div id="container"><div> |
當我們在用 jQuery 3 以前的版本時,如果執行如下程式碼:
1 2 3 4 5 6 7 |
var $elem = $('#container'); $elem.data({ 'my-property': 'hello' }); console.log($elem.data()); |
將會在控制檯得到如下結果:
1 |
{my-property: "hello"} |
而在 jQuery 3 中,我們將會得到如下結果:
1 |
{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),並觸發失敗回撥。一旦失敗回撥執行完畢,整個程式就將繼續推進,後續的成功回撥將被執行。
為了讓你更好地理解這個差異,讓我們來看一個小例子。比如我們有如下程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
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” 兩條訊息。那個異常將會被第一個失敗回撥處理,並且,一旦異常得到處理,那麼後續的成功回撥將被呼叫。
SVG 文件
沒有哪一個 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 時,請留意你正使用的外掛。
已修復的 Bug
jQuery 3 修復了以往版本中的一些非常重要的 bug。在本節中,我將著重介紹其中兩處,因為這兩者應該會對你寫程式碼的習慣帶來顯著影響。
width()
和 height()
的返回值將不再取整
jQuery 3 修復了 width()
、height()
和其它相關方法的一個 bug。這些方法的返回值將不再舍入取整,因為這種取整行為在某些情況下不便於對元素進行定位。
我們來詳細看一看。假設你一個寬度為 100px
的容器元素,它包含了三個子元素,寬度均為三分之一(即 33.333333%):
1 2 3 4 5 |
<div class="container"> <div>My name<div> <div>is<div> <div>Aurelio De Rosa<div> <div> |
在 jQuery 3 以前的版本中,如果你嘗試通過以下程式碼來獲取子元素的寬度……
1 |
$('.container div').width(); |
……那麼你得到結果將是 33
。原因在於 jQuery 會把 33.33333 這個值取整。而在 jQuery 3 中,這個 bug 已經被修復了,因此你將會得到更加精確的結果(即一個浮點數)。
wrapAll()
方法
wrapAll()
方法jQuery 3 還修復了 wrapAll()
方法中的一個 bug,這個 bug 出現在把一個函式作為引數傳給它的情況下。在 jQuery 3 以前的版本中,當一個函式被傳給 wrapAll()
方法時,它會把 jQuery 集合中的每個元素單獨包裹起來。換句話說,這種行為和把一個函式傳給 wrap()
時的行為是完全一樣的。
在修復這個問題的同時,還引入了另外一個變更:由於在 jQuery 3 中,這個函式只會呼叫一次了,那就無法把 jQuery 集合中每個元素都傳給它。因此,這個函式的執行上下文(this
)將只能指向當前 jQuery 集合中的第一個元素。
如何下載 jQuery 3 beta 1
既然你已經讀到了這裡,那說明你很可能想試試 jQuery 3 的第一個 beta 測試版。你可以通過以下兩個地址來獲取這個版本:
- 未壓縮版: https://code.jquery.com/jquery-3.0.0-beta1.js
- 壓縮版: https://code.jquery.com/jquery-3.0.0-beta1.min.js
當然,你還可以通過 npm 來下載:
1 |
npm install jquery@3.0.0-beta1 |
Conclusion
結論
很多人一直在唱衰 jQuery,說它在現代網頁開發中已經沒有一席之地了。但不管怎樣,jQuery 的開發仍在繼續,客觀的統計資料(在排名前一百萬名的網站中佔有率高達 78.5%)也讓這些論調不攻自破。
在本文中,我已經帶你瞭解了一遍 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 不相容的地方。當你修復了這些不相容問題之後,就可以安全地移除這個外掛了。