1. 程式人生 > >jQuery - 使用要點 - 迭代jQuery和非jQuery物件

jQuery - 使用要點 - 迭代jQuery和非jQuery物件

jQuery 提供命為 $.each() 的物件迭代器,以及命為 .each() 的集合迭代器,它們之間不可以互換。此外,還有一些命為 $.map().map() 的方法,可以簡化一些常見的迭代用例。

$.each() 是類迭代器函式,用以迴圈整個普通物件、陣列、類似陣列的物件集。普通物件通過其命名屬性迭代,而陣列和類似陣列的物件集通過其索引進行迭代。$.each() 實際上是傳統的 for 或者 for-in 迴圈的代替品。

var sum = 0;
var arr = [ 1, 2, 3, 4, 5 ];

// for 迴圈
for ( var i = 0, l = arr.length; i < l; i++ ) {
    sum += arr[ i ];
}
console.log( sum ); // 15

// 使用 $.each() 代替 for 迴圈
$.each( arr, function( index, value ){
    sum += value;
});
console.log( sum ); // 15

注意:上方的示例中,無需通過陣列索引(arr[index])的形式傳入值,值會以合宜的形式傳入 $.each() 的回撥函式。

var sum = 0;
var obj = {
    foo: 1,
    bar: 2
}

for (var item in obj) {
    sum += obj[ item ];
}
console.log( sum ); // 3

$.each( obj, function( key, value ) {
    sum += value;
});
console.log( sum ); // 3

注意:上方的示例中,無需通過 obj[key]

的形式傳入值,值會以合宜的形式傳入 $.each() 的回撥函式。

注意:$.each() 是針對普通物件、陣列、類似陣列的物件的函式,不是針對 jQuery 集合的函式,針對 jQuery 集合,請使用 .each() 函式。下方示例的操作是錯誤的。

// 這種操作形式是錯誤的!
$.each( $( "p" ), function() {
    // Do something
});

.each() 被使用於 jQuery 集合。該方法會迭代集合中每個匹配的元素,並且在回撥函式中處理每個匹配的元素。集合中匹配元素的索引值,會被作為第一個引數傳入回撥函式。集合中匹配元素的值作為第二個引數也會傳入回撥函式,但回撥函式是在當前匹配元素的上下文觸發的,所以 this

關鍵字指向當前匹配元素。

示例:

<ul>
    <li><a href="#">Link 1</a></li>
    <li><a href="#">Link 2</a></li>
    <li><a href="#">Link 3</a></li>
</ul>
$( "li" ).each( function( index, element ){
    console.log( $( this ).text() );
});
// 列印如下訊息:
// Link 1
// Link 2
// Link 3

.each() 的第二個引數,若 this 就代表該元素,那為什麼回撥函式中的第二個引數中要傳入 DOM 元素呢?

無論有意的或是無意的,執行時的環境上下文都有可能改變。當堅持使用 this 關鍵字,最終會造成混亂和降低程式碼的可讀性。下方示例:

$( "li" ).each( function( index, listItem ) {
 
    this === listItem; // true
 
    // 僅作示例
    $.ajax({
        success: function( data ) {
            // 上下文已經改變
            // this 關鍵字不再指向 listItem.
            this !== listItem; // true
        }
    });
 
});

有時 .each() 不是必須的,許多 jQuery 方法會隱式的迭代整個集合的元素,將行為應用於匹配的每一個元素。示例:

$( "li" ).each( function( index, el ) {
    $( el ).addClass( "newClass" );
});

// 同樣的功能
$( "li" ).addClass( "newClass" );

// 文件中的每一個 <li> 會新增 "newClass" 樣式類

另一方面,某些方法不會隱式的遍歷整個集合。若需要在給元素設定新值之前獲取該元素的資訊,此時 .each() 就是必須的。示例:

// 不會工作
$( "input" ).val( $( this ).val() + "%" );
// .val() 方法不會改變執行上下文,所以 this === window

// 應當的書寫方式
$( "input" ).each( function( i, el ) {
    var elem = $( el );
    elem.val( elem.val() + "%" );
});

下方列表展示需要使用 .each() 的方法:

  • .attr() getter模式
  • .css() getter模式
  • .data() getter模式
  • .height() getter模式
  • .html() getter模式
  • .innerHeight()
  • .innerWidth()
  • .offset() getter模式
  • .outerHeight()
  • .outerWidth()
  • .position()
  • .prop() getter模式
  • .scrollLeft() getter模式
  • .scrollTop() getter模式
  • .val() getter模式
  • .width() getter模式

注意在許多案例中,方法的 getter 模式會返回 jQuery 集合的第一個元素;而方法的 setter 模式是影響 jQuery 集合中所有匹配的元素。例外情況是:.text() 方法,會將所有匹配元素的文字串聯成字串返回。

setter 模式可以接受匿名回撥函式

// 以下程式碼功能相同
$( "input" ).each( function( i, el ) {
    var elem = $( el );
    elem.val( elem.val() + "%" );
});
 
$( "input" ).val(function( index, value ) {
    return value + "%";
});

使用隱式迭代時,要注意記住,例如:.children() .parend() 方法會作用於集合中的每個匹配元素,返回所有子節點或父節點的組合集合。

.map()

若要建立一個數組,或者基於匹配元素來連線字串,此時更推薦使用 .map()

// 下方兩個程式碼,功能相同
var newArr = [];
 
$( "li" ).each( function() {
    newArr.push( this.id );
});

$( "li" ).map( function(index, element) {
    return this.id;
}).get();

注意:.map() 方法鏈結尾的 .get() 實際上會返回 jQuery 封裝的集合,即使在回撥函式中返回的是字串。此時若要將 jQuery 封裝的集合變成字串,可以在 .get() 方法後使用普通的 JS 方法 .join() [陣列方法]。

$.map()

$.map() 工作於普通的 JavaScript 陣列,而 .map() 工作於 jQuery 元素集合。$.map() 返回一個普通的陣列,且無需呼叫 .get()

注意:$.map().map() 中的回撥函式的引數順序是不一樣的。

<li id="a"></li>
<li id="b"></li>
<li id="c"></li>
 
<script>
 
var arr = [{
    id: "a",
    tagName: "li"
}, {
    id: "b",
    tagName: "li"
}, {
    id: "c",
    tagName: "li"
}];
 
// 返回值為:陣列 [ "a", "b", "c" ]
$( "li" ).map( function( index, element ) {
    return element.id;
}).get();
 
// 返回值為:陣列 [ "a", "b", "c" ]
// 注意 $.map() 中,值引數變為回撥函式的第一個引數,索引變為回撥函式的第二個引數
$.map( arr, function( value, index ) {
    return value.id;
});
 
</script>