書寫高質量jQuery代碼的12條經驗

1、正確引用jQuery

  1. 儘量在body結束前才引入jQuery,而不是在head中。

  2. 藉助第三方提供的CDN來引入jQuery,同時注意當使用第三方CDN出現問題時,要引入本地的jQuery文件。

  3. 如果在</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區別。

2.1、一些規則

  • CSS解析引擎將自右向左計算每一條規則,它從關鍵選擇器開始,自右向左計算每一個選擇器,直到發現一個匹配的選擇器,如果沒有找到匹配的選擇器則放棄查找。

  • 使用較低層的規則通常更有效率。

  • 儘可能的具體化的選擇器——ID要比tag更好。

  • 避免不必要的冗餘。

通常請情況下,請保持選擇器簡單明瞭(比如充分使用ID選擇器),儘可能的使用關鍵選擇器更具體,無論對JavaScript還是CSS,這都可以加塊網站的速度。到目前爲止,無論使用哪一種瀏覽器,使用ID選擇器和當個類選擇器都是選中元素最快的方式。

2.2、避免多個ID選擇符

Id選擇符應該是唯一的,所以沒有必要添加額外的選擇符。

// 糟糕
$('div#myid');
$('div#footer a.myLink');
// 建議
$('#myid');
$('#footer .myLink');

在此強調,ID 選擇符應該是唯一的,不需要添加額外的選擇符,更不需要多個後代ID選擇符。

// 糟糕
$('#outer #inner');
// 建議
$('#inner');

2.3、避免隱式通用選擇符

通用選擇符有時是隱式的,不容易發現。

// 糟糕
$('.someclass :radio');
// 建議
$('.someclass input:radio');

2.4、避免通用選擇符

將通用選擇符放到後代選擇符中,性能非常糟糕。

// 糟糕
$('.container > *');
// 建議
$('.container').children();

2.5、選擇捷徑

精簡代碼的其中一種方式是利用編碼捷徑。

// 糟糕
if(collection.length > 0){..}
// 建議
if(collection.length){..}

2.6、爲選擇器指定上下文

默認情況下,當把一個選擇器傳遞給jQuery時,它將遍歷整個DOM,jQuery方法還具有一個未充分利用的參數,既可以將一個上下文參數傳入jQuery,以限制它只搜索DOM中特定的一部分。

//糟糕,會遍歷整個DOM
$(".class");
//建議,只搜索#id元素下的class,id指明搜索範圍
$(".class","#id");

jQuery選擇器的性能比較:

$(".class","#id") > $("#id .class") > $(".class")

3、緩存jQuery對象

緩存jQuery對象可以減少不必要的DOM查找,關於這點大家可以參考下緩存jQuery對象來提高性能。

// 糟糕
h = $('#element').height();
$('#element').css('height',h-20);
// 建議
$element = $('#element');
h = $element.height();
$element.css('height',h-20);

3.1、使用子查詢緩存的父元素

正如前面所提到的,DOM遍歷是一項昂貴的操作。典型做法是緩存父元素並在選擇子元素時重用這些緩存元素。

// 糟糕
var
    $container = $('#container'),
    $containerLi = $('#container li'),
    $containerLiSpan = $('#container li span');
// 建議 (高效)
var
    $container = $('#container '),
    $containerLi = $container.find('li'),
    $containerLiSpan= $containerLi.find('span');

4、變量

4.1、避免全局變量

jQuery與javascript一樣,一般來說,最好確保你的變量在函數作用域內。

// 糟糕
$element = $('#element');
h = $element.height();
$element.css('height',h-20);
// 建議
var $element = $('#element');
var h = $element.height();
$element.css('height',h-20);

4.2、使用匈牙利命名法

在變量前加$前綴,便於識別出jQuery對象。

// 糟糕
var first = $('#first');
var second = $('#second');
var value = $first.val();
// 建議 - 在jQuery對象前加$前綴
var $first = $('#first');
var $second = $('#second'),
var value = $first.val();

4.3、使用 Var 鏈(單 Var 模式)

將多條var語句合併爲一條語句,我建議將未賦值的變量放到後面。

var $first = $('#first'),
      $second = $('#second'),
      value = $first.val(),
      k = 3,
      cookiestring = 'SOMECOOKIESPLEASE',
      i,
      j,
      myArray = {};

5、正確使用事件委託

在新版jQuery中,更短的 on(“click”) 用來取代類似 click() 這樣的函數。在之前的版本中 on() 就是 bind()。自從jQuery 1.7版本後,on() 附加事件處理程序的首選方法。然而,出於一致性考慮,你可以簡單的全部使用 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' });  
}); 

6、精簡jQuery代碼

如在上述代碼中我們對jQuery代碼進行了適當的合併,類似的還有.attr()方法等,我們沒有寫成下邊的方式:

$('#t').on('click', 'td', function () {  
    $(this).css('color', 'red').css('background', 'yellow');  
});

6.1、合併函數

一般來說,最好儘可能合併函數。

// 糟糕
$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'
    });
});

6.2、鏈式操作

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);

7、減少DOM操作

剛開始使用jQuery時可能會頻繁的操作DOM,這是相當耗費性能的。如我們要在body中動態輸出一個表格,一些朋友會這樣寫:

//糟糕
var $t = $('body');  
$t.append('<table>');  
$t.append('<tr><td>1</td></tr>');  
$t.append('</table>');
//建議
$('body').append('<table><tr><td>1</td></tr></table>');

這樣在拼接完table串後再添加到body中,對DOM的操作只需一次。羣裏以前有朋友就因爲這個導致在IE下輸出時出現問題,而關於字符串的拼接可以參考下最快創建字符串的方法。

7.1、繁重的操作中分離元素

如果你打算對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);

7.2、最小化DOM更新

重佈局和重繪是WEB頁面中最常見的也是最昂貴的兩種操作。

  • 當改變樣式,而不改變頁面幾何佈局時,將會發生重繪。隱藏一個元素或者改變一個元素的背景色時都將導致一次重繪。

  • 當對頁面結構進行更新時,將導致頁面重佈局。

//糟糕
for(var i=0; i<10000; i++){
    $("#main table").append("<tr><td>aaaa</td></tr>");
}

//建議
var tablerow = "";
for(var i=0; i<10000; i++){
    tablerow  += "<tr><td>aaaa</td></tr>";
}
$("#main table").append(tablerow);

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、堅持最新版本

新版本通常更好:更輕量級,更高效。顯然,你需要考慮你要支持的代碼的兼容性。例如,2.0版本不支持ie 6/7/8。
摒棄棄用方法
關注每個新版本的廢棄方法是非常重要的並儘量避免使用這些方法。

// 糟糕 - live 已經廢棄
$('#stuff').live('click', function() {
  console.log('hooray');
});
// 建議
$('#stuff').on('click', function() {
  console.log('hooray');
});
// 注:此處可能不當,應爲live能實現實時綁定,delegate或許更合適

11、最後忠告

最後,我記錄這篇文章的目的是提高jQuery的性能和其他一些好的建議。如果你想深入的研究對這個話題你會發現很多樂趣。記住,jQuery並非不可或缺,僅是一種選擇。思考爲什麼要使用它。DOM操作?ajax?模版?css動畫?還是選擇符引擎?或許javascript微型框架或jQuery的定製版是更好的選擇。

雖然都是陳詞濫調,但是我發現還不能很好得做到上述所有,記錄下來希望自己能夠全部做到。

12、不使用jQuery

原生函數總是最快的,這點不難理解,在代碼書寫中我們不應該忘記原生JS。就先總結這幾條吧,每條建議並不難理解,但總結全面的話還是要花費不少時間的。如在減少代碼段中,如果需要根據條件從數組中得到新數組時,可以使用$.grep() 方法,如果你在使用jQuery時有自己心得的話,歡迎在留言中和大家分享!


參考資料:
《jQuery高級編程》[Cesar Otero,Rob Larsen],(譯)施宏斌,清華大學出版社,2013年4月第1版
http://mp.weixin.qq.com/s?__b...


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章