即将发布的jQuery 3 有哪些新特性
jQuery的横空出世,至今已有十个年头了,而它的长盛不衰显然不是没有理由的。jQuery是继prototype之后又一个优秀的Javascript库。它是轻量级的js库,它兼容CSS3,还兼容各种浏览器(IE6.0+,FF1.5+,Safari2.0+,Opera9.0+),jQuery2.0及后续版本将不再支持IE6/7/8浏览器。jQuery使用户能更方便地处理HTML(标准通用标记语言下的一个应用)、events、实现动画效果,并且方便地为网站提供AJAX交互。jQuery还有一个比较大的优势是,它的文档说明很全,而且各种应用也说得很详细,同时还有许多成熟的插件可供选择。
在未来的几周内,jQuery就将抵达一个重要的里程碑——正式发布3.0版本。jQuery3修复了大量的bug,增加了新的方法,同时移除了一些接口,并修改了少量接口的行为。在这篇文章中,我将为大家重点讲解jQuery3所引入的那些最重要的变化。
新增特性
我们先来讨论jQuery3中最重要的几个新增特性。
for...of循环
在jQuery3中,我们可以用for...of循环语句来迭代一个jQuery集合中的所有DOM元素。这种新的迭代方法是ECMAScript2015(即ES6)规范中的一部分。这个方法可以对“可迭代对象”(比如Array、Map、Set等)进行循环。
当使用这种新的迭代方法时,你在循环体内每次拿到的值并不是一个jQuery对象,而是一个DOM元素(译注:这一点跟.each()方法类似)。当你在对一个jQuery集合进行操作时,这个新的迭代方法可以少许改善你的代码。
为了搞清楚这种迭代方法到底是怎么工作的,我们来假设一个场景——你需要给页面中的每个input元素分配一个ID。在jQuery3之前,你可能会这样写:
var$inputs=$('input');for(vari=0;i<$inputs.length;i++){ $inputs[i].id='input-'+i; }
而在jQuery3中,你就可以这样写了:
var$inputs=$('input');vari=0; for(varinputof$inputs){ input.id='input-'+i++; }
(译注:其实jQuery自己是有个.each()方法的,可读性也不赖。)
$.get()和$.post()函数的新签名
jQuery3为$.get()和$.post()这两个工具函数增加了新签名,从而使得它们和$.ajax()的接口风格保持一致。新签名是这样的:
$.get([settings]) $.post([settings])
settings是一个对象,它包含多个属性。它的格式和你以前传给$.ajax()的参数格式是一样的。如果你想更清楚地了解这个参数对象,请参考$.ajax()页面中的相关描述。
$.get()和$.post()的参数对象与传给$.ajax()的参数相比,唯一的区别就是前者的method属性总是会被忽略。原因其实也很简单,$.get()和$.post()本身就已经预设了发起Ajax请求的HTTP方法了(显然$.get()就是GET,而$.post()就是POST)。也就是说,正常人类应该是不会想用$.get()方法来发送一个POST请求的。
假设有以下一段代码:
$.get({ url:'https://www.audero.it', method:'POST'//Thispropertyisignored //这个属性将被忽略});
不管我们把method属性写成什么,这个请求总是会以GET的方式发出去的。
采用requestAnimationFrame()来实现动画
所有现代浏览器(包括IE10及以上)都是支持requestAnimationFrame的。jQuery3将会在内部采用这个API来实现动画,以便达到更流畅、更省资源的动画效果。
unwrap()方法
jQuery3为unwrap()方法增加了一个可选的selector参数。这个方法的新签名是这样的:
unwrap([selector])
有了这个特性,你就可以给这个方法传入一个包含选择符表达式的字符串,用它来在父元素内进行匹配。如果存在匹配的子元素,则这个子元素的父层将被解除;如果没有匹配,则不进行操作。
有变更的特性
jQuery3还修改了一些特性的行为。
:visible和:hidden
jQuery3将会修改:visible和:hidden过滤器的含义。只要元素具有任何布局盒,哪怕宽高为零,也会被认为是:visible。举个例子,br元素和不包含内容的行内元素现在都会被:visible这个过滤器选中。
因此,如果你的页面中包含如下的结构:
<div></div><br/>
然后运行以下语句:
console.log($('body:visible').length);
在jQuery1.x和2.x中,你得到的结果会是0;但在jQuery3中,你会得到2。
data()方法
另一个重要的变化是跟data()方法有关的。现在它的行为已经变得跟DatasetAPI规范一致了。jQuery3将会把所有属性键名转换成驼峰形式。我们来详细看一下,以如下元素为例:
<divid="container"></div>
当我们在用jQuery3以前的版本时,如果运行如下代码:
var$elem=$('#container'); $elem.data({ 'my-property':'hello'});console.log($elem.data());
将会在控制台得到如下结果:
{my-property:"hello"}
而在jQuery3中,我们将会得到如下结果:
{myProperty:"hello"}
请注意,在jQuery3中,属性名已经变成了驼峰形式,横杠已经被去除了;而在以前的版本中,属性名会保持全小写,并原样保留横杠。
Deferred对象
jQuery3还改变了Deferred对象的行为。Deferred对象可以说是Promise对象的前身之一,它实现了对Promise/A+协议的兼容。这个对象以及它的历史都相当有意思。如果想要深入了解,你可以去阅读jQuery官方文档,也可以去看我写的书《jQuery实战(第三版)》——这本书也涵盖了jQuery3。
在jQuery1.x和2.x中,传给Deferred的回调函数内如果出现未捕获的异常,会立即中断程序的执行(译注:即静默失败,其实jQuery绝大多数回调函数的行为都是这样的)。而原生的Promise对象并非如此,它会抛出异常,并不断向上冒泡,直至到达window.onerror(通常冒泡的终点是这里)。如果你没有定义一个函数来处理这个错误事件的话(通常我们都不会这么做),那这个异常的信息将会被显示出来,此时程序的执行才会停止。
jQuery3将会遵循原生Promise对象的模式。因此,回调内产生的异常将会导致失败状态(rejection),并触发失败回调。一旦失败回调执行完毕,整个进程就将继续推进,后续的成功回调将被执行。
为了让你更好地理解这个差异,让我们来看一个小例子。比如我们有如下代码:
vardeferred=$.Deferred(); deferred .then(function(){ thrownewError('Anerror'); }) .then( function(){ console.log('Success1'); }, function(){ console.log('Failure1'); } ) .then( function(){ console.log('Success2'); }, function(){ console.log('Failure2'); } ); deferred.resolve();
在jQuery1.x和2.x中,只有第一个函数(也就是抛出错误的那个函数)会被执行到。此外,由于我们没有为window.onerror定义任何事件处理函数,控制台将会输出“UncaughtError:Anerror”,而且程序的执行将中止。
而在jQuery3中,整个行为是完全不同的。你将在控制台中看到“Failure1”和“Success2”两条消息。那个异常将会被第一个失败回调处理,并且,一旦异常得到处理,那么后续的成功回调将被调用。
SVG文档
没有哪一个jQuery版本(包括jQuery3)曾官方宣称支持SVG文档。不过事实上有很多方法是可以奏效的,此外还有一些方法在以前是不行的(比如操作类名的那些方法),但它们在jQuery3中也得到了更新。因此,在jQuery3中,你应该可以放心使用诸如addClass()和hasClass()这样的方法来操作SVG文档了。
已废弃、已移除的方法和属性
在增加了上述改进的同时,jQuery也移除、废弃了一些特性。
废弃bind()、unbind()、delegate()和undelegate()方法
jQuery在很久以前就引入了on()方法,它提供了一个统一的接口,用以取代bind()、delegate()和live()等方法。与此同时,jQuery还引入了off()这个方法来取代unbind()、undelegated()和die()等方法。从那时起,bind()、delegate()、unbind()和undelegate()就已经不再推荐使用了,但它们还是一直存在着。
jQuery3终于开始将这些方法标记为“废弃”了,并计划在未来的某个版本(很可能是jQuery4)中将它们彻底移除。因此,请在你的项目中统一使用on()和off()方法,这样你就不用担心未来版本的变更了。
移除load()、unload()和error()方法
jQuery3彻底抛弃了load()、unload()和error()等已经标记为废弃的方法。这些方法在很早以前(从jQuery1.8开始)就已经被标记为废弃了,但一直没有去掉。如果你正在使用的某款插件仍然依赖这些方法,那么升级到jQuery3会把你的代码搞挂。因此,在升级过程中请务必留意。
移除context、support和selector属性
jQuery3彻底抛弃了context、support和selector等已经标记为废弃的属性。同上,在升级到jQuery3时,请留意你正使用的插件。
已修复的Bug
jQuery3修复了以往版本中的一些非常重要的bug。在本节中,我将着重介绍其中两处,因为这两者应该会对你写代码的习惯带来显著影响。
width()和height()的返回值将不再取整
jQuery3修复了width()、height()和其它相关方法的一个bug。这些方法的返回值将不再舍入取整,因为这种取整行为在某些情况下不便于对元素进行定位。
我们来详细看一看。假设你一个宽度为100px的容器元素,它包含了三个子元素,宽度均为三分之一(即33.333333%):
<divclass="container"> <div>Myname</div> <div>is</div> <div>AurelioDeRosa</div></div>
在jQuery3以前的版本中,如果你尝试通过以下代码来获取子元素的宽度……
$('.containerdiv').width();
……那么你得到结果将是33。原因在于jQuery会把33.33333这个值取整。而在jQuery3中,这个bug已经被修复了,因此你将会得到更加精确的结果(即一个浮点数)。
wrapAll()方法
jQuery3还修复了wrapAll()方法中的一个bug,这个bug出现在把一个函数作为参数传给它的情况下。在jQuery3以前的版本中,当一个函数被传给wrapAll()方法时,它会把jQuery集合中的每个元素单独包裹起来。换句话说,这种行为和把一个函数传给wrap()时的行为是完全一样的。
在修复这个问题的同时,还引入了另外一个变更:由于在jQuery3中,这个函数只会调用一次了,那就无法把jQuery集合中每个元素都传给它。因此,这个函数的执行上下文(this)将只能指向当前jQuery集合中的第一个元素。
如何下载jQuery3beta1
既然你已经读到了这里,那说明你很可能想试试jQuery3的第一个beta测试版。你可以通过以下两个地址来获取这个版本:
未压缩版:https://code.jquery.com/jquery-3.0.0-beta1.js
压缩版:https://code.jquery.com/jquery-3.0.0-beta1.min.js
当然,你还可以通过npm来下载:
[code]npminstalljquery@3.0.0-beta1[/code]
结论
很多人一直在唱衰jQuery,说它在现代网页开发中已经没有一席之地了。但不管怎样,jQuery的开发仍在继续,客观的统计数据(在排名前一百万名的网站中占有率高达78.5%)也让这些论调不攻自破。
在本文中,我已经带你了解了一遍jQuery3将会带来的一些重大变化。或许你已经察觉到了,这个版本并不太可能搞挂你的既有项目,因为它引入的破坏性变更其实寥寥无几。不过,在升级到jQuery3的过程中,你还是有必要牢记一些关键点,比如Deferred对象的改进等等。同样,在升级某个第三方库时,也有必要检查一下该项目的兼容性情况,以便尽早发现任何非预期行为,避免某些功能失效。
译注
除了本文所提及的变更之外,jQuery3.0最大的变化就是彻底放弃对IE8的支持。jQuery团队做出这个决定的原因在于,微软已经在今年年初宣布停止对IE8~10的支持。因此,jQuery在3.0alpha阶段所发布的jQueryCompat项目也就没有继续存在的必要了。
不过,由于IE8仍然是中国大陆最流行的浏览器之一,对国内的开发者来说,在短期(甚至中期)内还不得不停留在jQuery1.x版本。
好吧,最后还是说个好消息吧。为帮助用户平滑升级,此次jQuery同样会为3.0版本提供迁移插件(jQueryMigrateplugin)。在把jQuery升级到3.0之后同时运行这个插件,即可确保基于jQuery1.x或2.x的既有业务代码正常运行;同时,它还将在控制台向你报告既有代码与jQuery3不兼容的地方。当你修复了这些不兼容问题之后,就可以安全地移除这个插件了。