jQuery 的橫空出世,至今已有十個(gè)年頭了,而它的長(zhǎng)盛不衰顯然不是沒(méi)有理由的。jQuery 提供了極為友好的接口,使得開(kāi)發(fā)者們可以方便地進(jìn)行 DOM 操作、發(fā)起 Ajax 請(qǐng)求、生成動(dòng)畫(huà)……不一而足。此外,與 DOM API 不同的是,jQuery 采用了 “混合模式”。這意味著你可以在任何一個(gè) jQuery 集合身上調(diào)用 jQuery 方法,而不用關(guān)心它到底包含了幾個(gè)元素(不管是零個(gè)、一個(gè)或多個(gè),都沒(méi)問(wèn)題)。
jQuery 3 修復(fù)了大量的 bug,增加了新的方法,同時(shí)移除了一些接口,并修改了少量接口的行為。
我們先來(lái)討論 jQuery 3 中最重要的幾個(gè)新增特性。
for...of
Loopfor...of
循環(huán)for...of
循環(huán)語(yǔ)句來(lái)迭代一個(gè) jQuery 集合中的所有 DOM 元素。這種新的迭代方法是 ECMAScript 2015(即 ES6)規(guī)范中的一部分。這個(gè)方法可以對(duì) “可迭代對(duì)象”(比如 Array
、Map
、Set
等)進(jìn)行循環(huán)。 當(dāng)使用這種新的迭代方法時(shí),你在循環(huán)體內(nèi)每次拿到的值并不是一個(gè) jQuery 對(duì)象,而是一個(gè) DOM 元素(譯注:這一點(diǎn)跟 .each()
方法類(lèi)似)。當(dāng)你在對(duì)一個(gè) jQuery 集合進(jìn)行操作時(shí),這個(gè)新的迭代方法可以少許改善你的代碼。
為了搞清楚這種迭代方法到底是怎么工作的,我們來(lái)假設(shè)一個(gè)場(chǎng)景——你需要給頁(yè)面中的每個(gè) input
元素分配一個(gè) ID。在 jQuery 3 之前,你可能會(huì)這樣寫(xiě):
var $inputs = $('input');
for(var i = 0; i < $inputs.length; i++) {
$inputs[i].id = 'input-' + i;
}
而在 jQuery 3 中,你就可以這樣寫(xiě)了:
var $inputs = $('input');
var i = 0;
for(var input of $inputs) {
input.id = 'input-' + i++;
}
$.get()
和 $.post()
函數(shù)的新簽名jQuery 3 為 $.get()
和 $.post()
這兩個(gè)工具函數(shù)增加了新簽名,從而使得它們和 $.ajax()
的接口風(fēng)格保持一致。新簽名是這樣的:
$.get([settings])
$.post([settings])
settings
是一個(gè)對(duì)象,它包含多個(gè)屬性。它的格式和你以前傳給 $.ajax()
的參數(shù)格式是一樣的。如果你想更清楚地了解這個(gè)參數(shù)對(duì)象,請(qǐng)參考 $.ajax()
頁(yè)面 中的相關(guān)描述。$.get()
和 $.post()
的參數(shù)對(duì)象與傳給 $.ajax()
的參數(shù)相比,唯一的區(qū)別就是前者的 method
屬性總是會(huì)被忽略。原因其實(shí)也很簡(jiǎn)單,$.get()
和 $.post()
本身就已經(jīng)預(yù)設(shè)了發(fā)起 Ajax 請(qǐng)求的 HTTP 方法了(顯然 $.get()
就是 GET,而 $.post()
就是 POST)。也就是說(shuō),正常人類(lèi)應(yīng)該是不會(huì)想用 $.get()
方法來(lái)發(fā)送一個(gè) POST 請(qǐng)求的。
假設(shè)有以下一段代碼:
$.get({
url: 'http://hgci.cn',
method: 'POST' // 這個(gè)屬性將被忽略
});
不管我們把 method
屬性寫(xiě)成什么,這個(gè)請(qǐng)求總是會(huì)以 GET 的方式發(fā)出去的。
requestAnimationFrame()
for AnimationsrequestAnimationFrame()
來(lái)實(shí)現(xiàn)動(dòng)畫(huà)所有現(xiàn)代瀏覽器(包括 IE10 及以上)都是支持 requestAnimationFrame
的。jQuery 3 將會(huì)在內(nèi)部采用這個(gè) API 來(lái)實(shí)現(xiàn)動(dòng)畫(huà),以便達(dá)到更流暢、更省資源的動(dòng)畫(huà)效果。
unwrap()
方法jQuery 3 為 unwrap()
方法增加了一個(gè)可選的 selector 參數(shù)。這個(gè)方法的新簽名是這樣的:
unwrap([selector])
:visible
和 :hidden
jQuery 3 將會(huì)修改 :visible
和 :hidden
過(guò)濾器的含義。只要元素具有任何布局盒,哪怕寬高為零,也會(huì)被認(rèn)為是 :visible
。舉個(gè)例子,br
元素和不包含內(nèi)容的行內(nèi)元素現(xiàn)在都會(huì)被 :visible
這個(gè)過(guò)濾器選中。
因此,如果你的頁(yè)面中包含如下的結(jié)構(gòu):
<div></div> <br />
然后運(yùn)行以下語(yǔ)句:
console.log($('body :visible').length);
0
;但在 jQuery 3 中,你會(huì)得到 2
。data()
方法另一個(gè)重要的變化是跟 data()
方法有關(guān)的?,F(xiàn)在它的行為已經(jīng)變得跟 Dataset API 規(guī)范 一致了。jQuery 3 將會(huì)把所有屬性鍵名轉(zhuǎn)換成駝峰形式。我們來(lái)詳細(xì)看一下,以如下元素為例:
<div id="container"></div>
當(dāng)我們?cè)谟?jQuery 3 以前的版本時(shí),如果運(yùn)行如下代碼:
var $elem = $('#container');
$elem.data({
'my-property': 'hello'
});
console.log($elem.data());
{my-property: "hello"}
{myProperty: "hello"}
Deferred
對(duì)象Deferred
對(duì)象的行為。Deferred
對(duì)象可以說(shuō)是 Promise
對(duì)象的前身之一,它實(shí)現(xiàn)了對(duì) Promise/A+ 協(xié)議 的兼容。這個(gè)對(duì)象以及它的歷史都相當(dāng)有意思。如果想要深入了解,你可以去閱讀 jQuery 官方文檔或者
《jQuery 實(shí)戰(zhàn)(第三版)》——這本書(shū)也涵蓋了 jQuery 3。在 jQuery 1.x 和 2.x 中,傳給 Deferred
的回調(diào)函數(shù)內(nèi)如果出現(xiàn)未捕獲的異常,會(huì)立即中斷程序的執(zhí)行(譯注:即靜默失敗,其實(shí) jQuery 絕大多數(shù)回調(diào)函數(shù)的行為都是這樣的)。而原生的 Promise
對(duì)象并非如此,它會(huì)拋出異常,并不斷向上冒泡,直至到達(dá) window.onerror
(通常冒泡的終點(diǎn)是這里)。如果你沒(méi)有定義一個(gè)函數(shù)來(lái)處理這個(gè)錯(cuò)誤事件的話(huà)(通常我們都不會(huì)這么做),那這個(gè)異常的信息將會(huì)被顯示出來(lái),此時(shí)程序的執(zhí)行才會(huì)停止。
jQuery 3 將會(huì)遵循原生 Promise
對(duì)象的模式。因此,回調(diào)內(nèi)產(chǎn)生的異常將會(huì)導(dǎo)致失敗狀態(tài)(rejection),并觸發(fā)失敗回調(diào)。一旦失敗回調(diào)執(zhí)行完畢,整個(gè)進(jìn)程就將繼續(xù)推進(jìn),后續(xù)的成功回調(diào)將被執(zhí)行。
為了讓你更好地理解這個(gè)差異,讓我們來(lái)看一個(gè)小例子。比如我們有如下代碼:
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();
window.onerror
定義任何事件處理函數(shù),控制臺(tái)將會(huì)輸出 “Uncaught Error: An error”,而且程序的執(zhí)行將中止。而在 jQuery 3 中,整個(gè)行為是完全不同的。你將在控制臺(tái)中看到 “Failure 1” 和 “Success 2” 兩條消息。那個(gè)異常將會(huì)被第一個(gè)失敗回調(diào)處理,并且,一旦異常得到處理,那么后續(xù)的成功回調(diào)將被調(diào)用。
addClass()
和 hasClass()
這樣的方法來(lái)操作 SVG 文檔了。SVGbind()
、unbind()
、delegate()
和 undelegate()
方法on()
方法,它提供了一個(gè)統(tǒng)一的接口,用以取代 bind()
、delegate()
和 live()
等方法。與此同時(shí),jQuery 還引入了 off()
這個(gè)方法來(lái)取代 unbind()
、undelegated()
和 die()
等方法。從那時(shí)起,bind()
、delegate()
、unbind()
和 undelegate()
就已經(jīng)不再推薦使用了,但它們還是一直存在著。
jQuery 3 終于開(kāi)始將這些方法標(biāo)記為 “廢棄” 了,并計(jì)劃在未來(lái)的某個(gè)版本(很可能是 jQuery 4)中將它們徹底移除。因此,請(qǐng)?jiān)谀愕捻?xiàng)目中統(tǒng)一使用 on()
和 off()
方法,這樣你就不用擔(dān)心未來(lái)版本的變更了。
load()
、unload()
和 error()
方法load()
、unload()
和 error()
等已經(jīng)標(biāo)記為廢棄的方法。這些方法在很早以前(從 jQuery 1.8 開(kāi)始)就已經(jīng)被標(biāo)記為廢棄了,但一直沒(méi)有去掉。如果你正在使用的某款插件仍然依賴(lài)這些方法,那么升級(jí)到 jQuery 3 會(huì)把你的代碼搞掛。因此,在升級(jí)過(guò)程中請(qǐng)務(wù)必留意。context
、support
和 selector
屬性context
、support
和 selector
等已經(jīng)標(biāo)記為廢棄的屬性。同上,在升級(jí)到 jQuery 3 時(shí),請(qǐng)留意你正使用的插件。width()
和 height()
的返回值將不再取整width()
、height()
和其它相關(guān)方法的一個(gè) bug。這些方法的返回值將不再舍入取整,因?yàn)檫@種取整行為在某些情況下不便于對(duì)元素進(jìn)行定位。我們來(lái)詳細(xì)看一看。假設(shè)你一個(gè)寬度為 100px
的容器元素,它包含了三個(gè)子元素,寬度均為三分之一(即 33.333333%):
<div class="container">
<div>My name</div>
<div>is</div>
<div>Aurelio De Rosa</div>
</div>
在 jQuery 3 以前的版本中,如果你嘗試通過(guò)以下代碼來(lái)獲取子元素的寬度
$('.container div').width();
33
。原因在于 jQuery 會(huì)把 33.33333 這個(gè)值取整。而在 jQuery 3 中,這個(gè) bug 已經(jīng)被修復(fù)了,因此你將會(huì)得到更加精確的結(jié)果(即一個(gè)浮點(diǎn)數(shù))。wrapAll()
方法wrapAll()
方法中的一個(gè) bug,這個(gè) bug 出現(xiàn)在把一個(gè)函數(shù)作為參數(shù)傳給它的情況下。在 jQuery 3 以前的版本中,當(dāng)一個(gè)函數(shù)被傳給 wrapAll()
方法時(shí),它會(huì)把 jQuery 集合中的每個(gè)元素單獨(dú)包裹起來(lái)。換句話(huà)說(shuō),這種行為和把一個(gè)函數(shù)傳給 wrap()
時(shí)的行為是完全一樣的。在修復(fù)這個(gè)問(wèn)題的同時(shí),還引入了另外一個(gè)變更:由于在 jQuery 3 中,這個(gè)函數(shù)只會(huì)調(diào)用一次了,那就無(wú)法把 jQuery 集合中每個(gè)元素都傳給它。因此,這個(gè)函數(shù)的執(zhí)行上下文(this
)將只能指向當(dāng)前 jQuery 集合中的第一個(gè)元素。
Deferred
對(duì)象的改進(jìn)等等。同樣,在升級(jí)某個(gè)第三方庫(kù)時(shí),也有必要檢查一下該項(xiàng)目的兼容性情況,以便盡早發(fā)現(xiàn)任何非預(yù)期行為,避免某些功能失效。
更多建議: