寫這篇的動機是常在專案看到「古典式」JavaScript陣列處理,例如:跑迴圈將物件陣列的某個字串屬取出轉成字串陣列、篩選物件陣列取得特定類別的集合。用for迴圈處理沒什麼不對,但既然專案已經用了jQuery,能一行搞定卻寫成三五行不免可惜(程式又不按行數計酬,寫愈多手愈酸咩 XD)。感覺上還有些朋友不認識$.map()$.grep()這兩個好東西,故寫篇文章推薦一下。

若用LINQ做比方,$.map()相當於 .Select(o => 傳回數值或其他型別物件).ToArray(),可將物件陣列轉換成某個屬性或其他型別物件組成的陣列;$.grep()則類似 .Where(o => 傳回布林值).ToArray(),可過濾陣列保留符合條件的元素項目。

使用概念如下,輸入陣列,執行後傳回陣列:

$.map(array, function(element, index) { return 新陣列的元素; });
(註:若輸出陣列想略過特定元素,就return null或undefined)

$.grep(array, function(element, index) { return true或false; });
(傳回true的元素才會出現在篩選結果)

來看實例,以下程式有四個範例,分別用傳統方法及$.map(), $.grep()實現「物件陣列轉字串陣列」以及「過濾物件陣列保留特定類別」,程式不複雜,直接看程式碼,開始想想可以用在哪些專案角萿吧!
線上展示

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>jQuery map & grep</title>
</head>
<body>
  <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
  <script>
    function Product(category, name) {
      this.category = category;
      this.name = name;
    }
    var items = [
      new Product("Phone", "iPhone4S"),
      new Product("Phone", "Lumia 920"),
      new Product("Phone", "小米"),
      new Product("Pad", "Nexus7"),
      new Product("Pad", "iPad")
    ];
    //範例一:取得產品名稱字串陣列
    var names = [];
    for (var i = 0; i < items.length; i++) {
      names.push(items[i].name);
    }
    //同場加映:JSON.stringify時傳入額外參數加上縮排
    alert(JSON.stringify(names, null, 4));
    //範例二:篩選手機類的產品陣列
    var phones = [];
    $.each(items, function(i, item) {
      if (item.category == "Phone")
        phones.push(item);
    });
    alert(JSON.stringify(phones, null, 4));
    
    //jQuery改良版
    
    //範例三:取得產品名稱字串陣列$.map()
    var names = $.map(items, function(item) { 
      return item.name; 
    });
    alert(JSON.stringify(names, null, 4));
    //範例四:篩選手機類的產品陣列$.grep()
    var phones = $.grep(items, function(item) {
      return item.category == "Phone";
    });
    alert(JSON.stringify(phones, null, 4));
  </script>
 
</body>
</html>

Comments

# by HamielKuo

您好, 有看到文章內有用到[$.each(],我這邊有遇到下面的情況,目前是採用[for]來解決效能問題,想請問是否有其他解決方式? 情況: 專案用Kendo UI Grid,需在每次重整(如跳轉grid 分頁)時將Grid內的下拉選單內容改為Grid欄位對應的顯示,有採用[$.each(],但後來遇到效能問題,故回頭改成用[for]來解決,感覺是有快了些.

# by Phoenix

看起來好好用的東西,好後悔以前不認識他呀QQ

# by Cash

黑大.. 範例三 的變數名稱應該是 names

# by Billy

雖然有map, grep 等新方法,但是萬變不離其宗,若追求速度的話,沒有方法可以比單純的 for loop 更快的了,而且亦是永遠不會忘記、不算複雜的方法。 map, grep 從上述的程式碼看來,沒有比for loop 簡單多少。

# by Jeffrey

to HamielKuo, 我非常好奇使用$.each()效能不佳,改用for才克服的案例,依直覺應不致有如此大的差異,可否再多提供一些細節? to Cash, 謝謝指正。 to Billy, 同意。for 迴圈具備單純,不需學習的特性。是否採用可視個人偏好,但學會它就多一項選擇,有利無害,即便最後決定用for比較好,考量應是「比較喜歡for」而非「不知道有$.grep()/$.map()」,也算文章有達到它的效果。

# by Billy

同意,讓我多介紹一個function - reduce(),從左到右處理陣列元素,最後返回一個數值。 簡單的例子: var total = [0, 1, 2, 3].reduce(function(a, b) { return a + b; }); https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce Map + Reduce 是functional programming一個經典組合 https://en.wikipedia.org/wiki/MapReduce

# by Jeffrey

to Billy, reduce()用來累計或比max/min很好用,也是可替代for的好工具,已筆記,感謝分享。

Post a comment