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>