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() 是針對普通物件、陣列、類似陣列的物件的函式,不是針對 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>