jQuery_编写更好代码的建议

1.缓存变量

DOM遍历是昂贵的,所以尽量将会重用的元素缓存。

// 糟糕

h = $('#element').height();

$('#element').css('height',h-20);

// 建议

$element = $('#element');

h = $element.height();

$element.css('height',h-20);

2.避免全局变量

jQuery与javascript一样,一般来说,最好确保你的变量在函数作用域内。

// 糟糕

$element = $('#element');

h = $element.height();

$element.css('height',h-20);

// 建议

var $element = $('#element');

var h = $element.height();

$element.css('height',h-20);

3.使用匈牙利命名法

在变量前加$前缀,便于识别出jQuery对象。

// 糟糕

var first = $('#first');

var second = $('#second');

var value = $first.val();

// 建议 - 在jQuery对象前加$前缀

var $first = $('#first');

var $second = $('#second'),

var value = $first.val();

4.使用 Var 链(单 Var 模式)

将多条var语句合并为一条语句,我建议将未赋值的变量放到后面。

var

  $first = $('#first'),

  $second = $('#second'),

  value = $first.val(),

  k = 3,

  cookiestring = 'SOMECOOKIESPLEASE',

  i,

  j,

  myArray = {};

5.请使用’On’

在新版jQuery中,更短的 on(“click”) 用来取代类似 click() 这样的函数。在之前的版本中 on() 就是 bind()。自从jQuery 1.7版本后,on()?附加事件处理程序的首选方法。然而,出于一致性考虑,你可以简单的全部使用 on()方法。

// 糟糕

$first.click(function(){

    $first.css('border','1px solid red');

    $first.css('color','blue');

});

$first.hover(function(){

    $first.css('border','1px solid red');

})

// 建议

$first.on('click',function(){

    $first.css('border','1px solid red');

    $first.css('color','blue');

})

$first.on('hover',function(){

    $first.css('border','1px solid red');

})

6.精简javascript

一般来说,最好尽可能合并函数。

// 糟糕

$first.click(function(){

    $first.css('border','1px solid red');

    $first.css('color','blue');

});

// 建议

$first.on('click',function(){

    $first.css({

        'border':'1px solid red',

        'color':'blue'

    });

});

7.链式操作

jQuery实现方法的链式操作是非常容易的。下面利用这一点。

// 糟糕

$second.html(value);

$second.on('click',function(){

    alert('hello everybody');

});

$second.fadeIn('slow');

$second.animate({height:'120px'},500);

// 建议

$second.html(value);

$second.on('click',function(){

    alert('hello everybody');

}).fadeIn('slow').animate({height:'120px'},500);

8.维持代码的可读性

伴随着精简代码和使用链式的同时,可能带来代码的难以阅读。添加缩紧和换行能起到很好的效果。

// 糟糕

$second.html(value);

$second.on('click',function(){

    alert('hello everybody');

}).fadeIn('slow').animate({height:'120px'},500);

// 建议

$second.html(value);

$second

    .on('click',function(){ alert('hello everybody');})

    .fadeIn('slow')

    .animate({height:'120px'},500);

9.选择短路求值

短路求值是一个从左到右求值的表达式,用 &&(逻辑与)或 || (逻辑或)操作符。

// 糟糕

function initVar($myVar) {

    if(!$myVar) {

        $myVar = $('#selector');

    }

}

// 建议

function initVar($myVar) {

    $myVar = $myVar || $('#selector');

}

10.选择捷径

精简代码的其中一种方式是利用编码捷径。

// 糟糕

if(collection.length > 0){..}

// 建议

if(collection.length){..}

11.繁重的操作中分离元素

如果你打算对DOM元素做大量操作(连续设置多个属性或css样式),建议首先分离元素然后在添加。

// 糟糕

var

    $container = $("#container"),

    $containerLi = $("#container li"),

    $element = null;

$element = $containerLi.first(); 

//... 许多复杂的操作

// better

var

    $container = $("#container"),

    $containerLi = $container.find("li"),

    $element = null;

$element = $containerLi.first().detach(); 

//... 许多复杂的操作

$container.append($element);

12.熟记技巧

你可能对使用jQuery中的方法缺少经验,一定要查看的文档,可能会有一个更好或更快的方法来使用它。

// 糟糕

$('#id').data(key,value);

// 建议 (高效)

$.data('#id',key,value);

13.使用子查询缓存的父元素

正如前面所提到的,DOM遍历是一项昂贵的操作。典型做法是缓存父元素并在选择子元素时重用这些缓存元素。

// 糟糕

var

    $container = $('#container'),

    $containerLi = $('#container li'),

    $containerLiSpan = $('#container li span');

// 建议 (高效)

var

    $container = $('#container '),

    $containerLi = $container.find('li'),

    $containerLiSpan= $containerLi.find('span');

14.避免通用选择符

将通用选择符放到后代选择符中,性能非常糟糕。

// 糟糕

$('.container > *'); 

// 建议

$('.container').children();

15.避免隐式通用选择符

通用选择符有时是隐式的,不容易发现。

// 糟糕

$('.someclass :radio'); 

// 建议

$('.someclass input:radio');

16.优化选择符

例如,Id选择符应该是唯一的,所以没有必要添加额外的选择符。

// 糟糕

$('div#myid'); 

$('div#footer a.myLink');

// 建议

$('#myid');

$('#footer .myLink');

17.避免多个ID选择符

在此强调,ID 选择符应该是唯一的,不需要添加额外的选择符,更不需要多个后代ID选择符。

// 糟糕

$('#outer #inner'); 

// 建议

$('#inner');

18.坚持最新版本

新版本通常更好:更轻量级,更高效。显然,你需要考虑你要支持的代码的兼容性。例如,2.0版本不支持ie 6/7/8。

摒弃弃用方法 关注每个新版本的废弃方法是非常重要的并尽量避免使用这些方法。

// 糟糕 - live 已经废弃

$('#stuff').live('click', function() {

  console.log('hooray');

});

// 建议

$('#stuff').on('click', function() {

  console.log('hooray');

});

// 注:此处可能不当,应为live能实现实时绑定,delegate或许更合适

19.利用CDN

谷歌的CND能保证选择离用户最近的缓存并迅速响应。(使用谷歌CND请自行搜索地址,此处地址以不能使用,推荐jquery官网提供的CDN)。

必要时组合jQuery和javascript原生代码

如上所述,jQuery就是javascript,这意味着用jQuery能做的事情,同样可以用原生代码来做。原生代码(或?vanilla)的可读性和可维护性可能不如jQuery,而且代码更长。但也意味着更高效(通常更接近底层代码可读性越差,性能越高,例如:汇编,当然需要更强大的人才可以)。牢记没有任何框架能比原生代码更小,更轻,更高效(注:测试链接已失效,可上网搜索测试代码)。

鉴于vanilla 和 jQuery之间的性能差异,我强烈建议吸收两人的精华,使用(可能的话)和jQuery等价的原生代码。

20. 用对选择器 

在jQuery中,你可以用多种选择器,选择同一个网页元素。每种选择器的性能是不一样的,你应该了解它们的性能差异。 

(1)最快的选择器:id选择器和元素标签选择器 

举例来说,下面的语句性能最佳: 

$('#id') 

$('form') 

$('input') 

遇到这些选择器的时候,jQuery内部会自动调用浏览器的原生方法(比如getElementById()),所以它们的执行速度快。 

(2)较慢的选择器:class选择器   

$('.className')的性能,取决于不同的浏览器。 

Firefox、Safari、Chrome、Opera浏览器,都有原生方法getElementByClassName(),所以速度并不慢。但是,IE5-IE8都没有部署这个方法,所以这个选择器在IE中会相当慢。 

(3)最慢的选择器:伪类选择器和属性选择器 

先来看例子。找出网页中所有的隐藏元素,就要用到伪类选择器:   $(':hidden') 

属性选择器的例子则是:   $('[attribute=value]') 

这两种语句是最慢的,因为浏览器没有针对它们的原生方法。但是,一些浏览器的新版本,增加了querySelector()和querySelectorAll()方法,因此会使这类选择器的性能有大幅提高。 

最后是不同选择器的性能比较图。   

可以看到,ID选择器遥遥领先,然后是标签选择器,第三是Class选择器,其他选择器都非常慢。 

21. 理解子元素和父元素的关系 

下面六个选择器,都是从父元素中选择子元素。你知道哪个速度最快,哪个速度最慢吗? 

$('.child', $parent) 

$parent.find('.child') 

$parent.children('.child') 

$('#parent > .child') 

$('#parent .child') 

$('.child', $('#parent')) 

(1) $('.child', $parent) 

这条语句的意思是,给定一个DOM对象,然后从中选择一个子元素。jQuery会自动把这条语句转成$.parent.find('child'),这会导致一定的性能损失。它比最快的形式慢了5%-10%。 

(2) $parent.find('.child') 

这条是最快的语句。.find()方法会调用浏览器的原生方法(getElementById,getElementByName,getElementByTagName等等),所以速度较快。   

(3) $parent.children('.child') 

这条语句在jQuery内部,会使用$.sibling()和javascript的nextSibling()方法,一个个遍历节点。它比最快的形式大约慢50%。 

(4) $('#parent > .child') 

jQuery内部使用Sizzle引擎,处理各种选择器。Sizzle引擎的选择顺序是从右到左,所以这条语句是先选.child,然后再一个个过滤出父元素#parent,这导致它比最快的形式大约慢70%。 

(5) $('#parent .child') 

这条语句与上一条是同样的情况。但是,上一条只选择直接的子元素,这一条可以于选择多级子元素,所以它的速度更慢,大概比最快的形式慢了77%。 

(6) $('.child', $('#parent')) 

jQuery内部会将这条语句转成$('#parent').find('.child'),比最快的形式慢了23%。 

所以,最佳选择是$parent.find('.child')。而且,由于$parent往往在前面的操作已经生成,jQuery会进行缓存,所以进一步加快了执行速度。 

22. 不要过度使用jQuery 

jQuery速度再快,也无法与原生的javascript方法相比。所以有原生方法可以使用的场合,尽量避免使用jQuery。 

请看下面的例子,为a元素绑定一个处理点击事件的函数: 

$('a').click(function(){ 

  alert($(this).attr('id')); 

}); 

这段代码的意思是,点击a元素后,弹出该元素的id属性。为了获取这个属性,必须连续两次调用jQuery,第一次是$(this),第二次是attr('id')。 

事实上,这种处理完全不必要。更正确的写法是,直接采用javascript原生方法,调用this.id: 

$('a').click(function(){ 

  alert(this.id); 

}); 

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

6. 使用链式写法 

jQuery的一大特点,就是允许使用链式写法。 

$('div').find('h3').eq(2).html('Hello'); 

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

7. 事件的委托处理(Event Delegation) 

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

利用这一点,可以大大简化事件的绑定。比如,有一个表格(table元素),里面有100个格子(td元素),现在要求在每个格子上面绑定一个点击事件(click),请问是否需要将下面的命令执行100次? 

$("td").bind("click", function(){ 

  $(this).toggleClass("click"); 

}); 

回答是不需要,我们只要把这个事件绑定在table元素上面就可以了,因为td元素发生点击事件之后,这个事件会"冒泡"到父元素table上面,从而被监听到。 

因此,这个事件只需要在父元素绑定1次即可,而不需要在子元素上绑定100次,从而大大提高性能。这就叫事件的"委托处理",也就是子元素"委托"父元素处理这个事件。 

具体的写法有两种。第一种是采用.delegate()方法: 

$("table").delegate("td", "click", function(){ 

  $(this).toggleClass("click"); 

}); 

第二种是采用.live()方法: 

$("table").each(function(){ 

  $("td", this).live("click", function(){ 

    $(this).toggleClass("click"); 

  }); 

}); 

这两种写法基本等价。唯一的区别在于,.delegate()是当事件冒泡到指定的父元素时触发,.live()则是当事件冒泡到文档的根元素后触发,因此.delegate()比.live()稍快一点。此外,这两种方法相比传统的.bind()方法还有一个好处,那就是对动态插入的元素也有效,.bind()只对已经存在的DOM元素有效,对动态插入的元素无效。 

根据测试,委托处理比不委托处理,快了几十倍。在委托处理的情况下,.delegate()又比.live()大约快26%。 

8. 少改动DOM结构   

(1)改动DOM结构开销很大,因此不要频繁使用.append()、.insertBefore()和.insetAfter()这样的方法。 

如果要插入多个元素,就先把它们合并,然后再一次性插入。根据测试,合并插入比不合并插入,快了将近10倍。 

(2)如果你要对一个DOM元素进行大量处理,应该先用.detach()方法,把这个元素从DOM中取出来,处理完毕以后,再重新插回文档。根据测试,使用.detach()方法比不使用时,快了60%。 

(3)如果你要在DOM元素上储存数据,不要写成下面这样: 

var elem = $('#elem'); 

elem.data(key,value); 

而要写成 

var elem = $('#elem'); 

$.data(elem,key,value); 

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

9. 正确处理循环 

循环总是一种比较耗时的操作,如果可以使用复杂的选择器直接选中元素,就不要使用循环,去一个个辨认元素。

javascript原生循环方法for和while,要比jQuery的.each()方法快,应该优先使用原生方法。 

10. 尽量少生成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对象操作,所以相对开销较小,速度比较快

1.正确引用jQuery

尽量在body结束前才引入jQuery,而不是在head中。

借助第三方提供的CDN来引入jQuery,同时注意当使用第三方CDN出现问题时,要引入本地的jQuery文件。

如果在</body>前引入script文件的话,就不用写document.ready了,因为这时执行js代码时DOM已经加载完毕了。

<body>  

    <script src="http://lib.sinaapp.com/js/jquery11/1.8/jquery.min.js"></script>  

    <script>window.jQuery || document.write('<script src="jquery1.8.min.js">\x3C/script>')</script>  

</body>  

 2.优化jQuery选择器

高效正确的使用jQuery选择器是熟练使用jQuery的基础,而掌握jQuery选择器需要一定的时间积累,我们开始学习jQuery时就应该注意选择器的使用。

<div id="nav" class="nav">  

    <a class="home" href="http://www.jquery001.com">jQuery学习网</a>  

    <a class="articles" href="http://www.jquery001.com/articles/">jQuery教程</a>  

</div>  

如果我们选择class为home的a元素时,可以使用下边代码:

$('.home');  //1  

$('#nav a.home');  //2  

$('#nav').find('a.home');  //3  

方法1会使jQuery在整个DOM中查找class为home的a元素,性能可想而知。

方法2为要查找的元素添加了上下文,在这里变为查找id为nav的子元素,查找性能得到了很大提升。

方法3使用了find方法,它的速度更快,所以方法三最好。

关于jQuery选择器的性能优先级,ID选择器快于元素选择器,元素选择器快于class选择器。因为ID选择器和元素选择器是原生的JavaScript操作,而类选择器不是,大家顺便可以看下find context 区别,find() children区别。

3.缓存jQuery对象

缓存jQuery对象可以减少不必要的DOM查找,关于这点大家可以参考下缓存jQuery对象来提高性能。

4.正确使用事件委托

事件委托可以使事件更好的执行,在动态添加的元素上绑定事件也需要委托来实现,在新版本的jQuery中推荐大家使用on来给元素绑定一个或多个事件的处理函数。

<table id="t">  

    <tr>  

        <td>我是单元格</td>  

    </tr>  

</table>  

比如我们要在上边的单元格上绑定一个单击事件,不注意的朋友可能随手写成下边的样子:

$('#t').find('td').on('click', function () {  

    $(this).css({ 'color': 'red', 'background': 'yellow' });  

});  

 这样会为每个td绑上事件,在为100个单元格绑定click事件的测试中,两者性能相差7倍之多,好的做法应该是下边写法:

$('#t').on('click', 'td', function () {  

    $(this).css({ 'color': 'red', 'background': 'yellow' });  

});  

 5.精简jQuery代码

如在上述代码中我们对jQuery代码进行了适当的合并,类似的还有.attr()方法等,我们没有写成下边的方式: 

.代码 

$('#t').on('click', 'td', function () {  

    $(this).css('color', 'red').css('background', 'yellow');  

});  

6.减少DOM操作

刚开始使用jQuery时可能会频繁的操作DOM,这是相当耗费性能的。如我们要在body中动态输出一个表格,一些朋友会这样写:

//worse

var $t = $('body');  

$t.append('<table>');  

$t.append('<tr><td>1</td></tr>');  

$t.append('</table>');  

//better 

.代码 

$('body').append('<table><tr><td>1</td></tr></table>');  

这样在拼接完table串后再添加到body中,对DOM的操作只需一次。群里以前有朋友就因为这个导致在IE下输出时出现问题,而关于字符串的拼接可以参考下最快创建字符串的方法。

7.不使用jQuery

原生函数总是最快的,这点不难理解,在代码书写中我们不应该忘记原生JS。

就先总结这几条吧,每条建议并不难理解,但总结全面的话还是要花费不少时间的。如在减少代码段中,如果需要根据条件从数组中得到新数组时,可以使用$.grep() 方法,如果你在使用jQuery时有自己心得的话,欢迎在留言中和大家分享!