高效使用jQuery

有了jQuery,天天喝茶水 根据《jQuery最佳实践》整理

使用最新版的jQuery

使用合适的选择器

  1. 最快的选择器:id选择器和元素标签选择器 遇到这些选择器的时候,jQuery内部会自动调用浏览器的原生方法
  2. 较慢的选择器:class选择器 IE5-8没有getElementsByClassName这个原生方法,这个选择器在IE中会相当慢。
  3. 最慢的选择器:伪类选择器和属性选择器 IE5-7中没有querySelector和querySelectorAll原生方法

子元素和父元素的关系


$('child', $parent);
$parent.find('child');
$parent.children('child');
$('parent > child');
$('parent child');
$('child', $('parent'));
        
  1. $('child', $parent); jQuery将这条语句转换成$parent.find('child'),转换过程损耗了性能,比最快的形式慢5%-10%。
  2. $parent.find('child'); 最快的方法。.find()方法会调用浏览器的原生方法(getElementById,getElementByName,getElementByTagName等等),所以速度较快。
  3. $parent.children('child'); 这条语句在jQuery内部会使用$.sibling()和原生方法nextSibling,依次遍历节点,比最快的形式慢大约50%。
  4. $('parent > child'); jQuery内部使用Sizzle引擎,处理各种选择器。Sizzle引擎的选择顺序是从右到左,所以这条语句是先选child,然后再一个个过滤出父元素parent,这导致它比最快的形式大约慢70%。
  5. $('parent child'); 这条语句与上一条是同样的情况。但是,上一条只选择直接的子元素,这一条可以于选择多级子元素,所以它的速度更慢,大概比最快的形式慢了77%。
  6. $('child', $('parent')); jQuery内部会将这条语句转成$('parent').find('child'),比最快的形式慢了23%。

不要过度使用jQuery

jQuery速度再快,也无法与原生的javascript方法相比。所以有原生方法可以使用的场合,尽量避免使用jQuery。以最简单的选择器为例,document.getElementById("foo")要比$("#foo")快10多倍。


$('a').click(function(){
    alert($(this).attr('id'));
});
$('a').click(function(){
    alert(this.id);
});
        

根据测试,this.id的速度比$(this).attr('id')快了20多倍。

做好缓存

选中某一个网页元素,是开销很大的步骤。所以,使用选择器的次数应该越少越好,并且尽可能缓存选中的结果,便于以后反复使用。


// 不使用缓存
jQuery('#top').find('p.classA');
jQuery('#top').find('p.classB');

// 使用缓存
var cached = jQuery('#top');
cached.find('p.classA');
cached.find('p.classB');
        

根据测试,缓存比不缓存,快了2-3倍。

使用链式写法

采用链式写法时,jQuery自动缓存每一步的结果,因此比非链式写法要快。根据测试,链式写法比(不使用缓存的)非链式写法,大约快了25%。

事件的委托处理

javascript的事件模型,采用"冒泡"模式,也就是说,子元素的事件会逐级向上"冒泡",成为父元素的事件。


// 事件的"委托处理",也就是子元素"委托"父元素处理这个事件。
$("table").on("click", "td", function(){
    $(this).toggleClass("click");
});

// 更好的写法,则是把事件绑定在document对象上面。
$(document).on("click", "td", function(){
    $(this).toggleClass("click");
});

// 如果要取消事件的绑定,就使用off()方法。
$(document).off("click", "td");
        

少改动DOM结构

  1. 改动DOM结构开销很大,因此不要频繁使用.append()、.insertBefore()和.insetAfter()这样的方法。如果要插入多个元素,就先把它们合并,然后再一次性插入。根据测试,合并插入比不合并插入,快了将近10倍。
  2. 如果你要对一个DOM元素进行大量处理,应该先用.detach()方法,把这个元素从DOM中取出来,处理完毕以后,再重新插回文档。根据测试,使用.detach()方法比不使用时,快了60%。
  3. 插入html代码的时候,浏览器原生的innterHTML()方法比jQuery对象的html()更快。

正确处理循环

循环总是一种比较耗时的操作,如果可以使用复杂的选择器直接选中元素,就不要使用循环,去一个个辨认元素。javascript原生循环方法for和while,要比jQuery的.each()方法快,应该优先使用原生方法。

尽量少生成jQuery对象

每当你使用一次选择器(比如$('#id')),就会生成一个jQuery对象。jQuery对象是一个很庞大的对象,带有很多属性和方法,会占用不少资源。所以,尽量少生成jQuery对象。

举例来说,许多jQuery方法都有两个版本,一个是供jQuery对象使用的版本,另一个是供jQuery函数使用的版本。下面两个例子,都是取出一个元素的文本,使用的都是text()方法。


// 你既可以使用针对jQuery对象的版本:
var $text = $("#text");
var $ts = $text.text();

// 也可以使用针对jQuery函数的版本:
var $text = $("#text");
var $ts = $.text($text);
        

由于后一种针对jQuery函数的版本不通过jQuery对象操作,所以相对开销较小,速度比较快。

使用作用链最短的方法

严格地说,这一条原则对所有Javascript编程都适用,而不仅仅针对jQuery。

我们知道,Javascript的变量采用链式作用域。读取变量的时候,先在当前作用域寻找该变量,如果找不到,就前往上一层的作用域寻找该变量。这样的设计,使得读取局部变量比读取全局变量快得多。


// 如果你要在DOM元素上储存数据,不要写成下面这样:
var elem = $('#elem');
elem.data(key,value);

// 而要写成
var elem = $('#elem');
$.data(elem[0],key,value);
        

根据测试,后一种写法要比前一种写法,快了将近10倍。因为elem.data()方法是定义在jQuery函数的prototype对象上面的,而$.data()方法是定义jQuery函数上面的,调用的时候不从复杂的jQuery对象上调用,所以速度快得多。