forEach是最常用到的数组扩展方法之一,相当于参数化循环数组,它简单的在数组的每一个元素上应用传入的函数,这也意味着只有存在的元素会被访问和处理。
[1,2,3,"csser"].forEach(alert);这里,作为参数传入的函数会被应用在数组中的每一项,本例中传入的函数为alert,那么这和for循环有什么不同呢,如:
var array = [1,2,3,"csser"];
for ( var k = 0, length = array.length; k < length; k++ ) {
alert(array[k]);
}
因为不能指向一个没有变量的数组,我们定义了一个额外的变量array,循环计数我们使用变量k。因为我们在通过for进行循环,代码本身变长了,当然我们也可以使用另一个循环(while),也可以将代码封装在一个通用函数内部,但是这种抽象仍然不如forEach的方式。
如果我们用console.log替换处理函数,将可以得到另外的有趣结果:
[1,2,3,"csser"].forEach(console.log);// 结果:
// 1, 0, Array[1, 2, 3, "csser"]
// 2, 1, Array[1, 2, 3, "csser"]
// 3, 2, Array[1, 2, 3, "csser"]
// csser, 3, Array[1, 2, 3, "csser"]
调试函数console.log(Opera Dragonfly 或 Firebug提供)能接受任意个参数,这里forEach函数每次调用console.log时会传入3个参数。显而易见,这3个参数分别是:当前项、当前项索引和数组本身,由此我们也可以创建任意定义3个参数的函数用于数组遍历处理:
var sum = 0;[1,2,3,"csser"].forEach(function (item, index, array) {
console.log(array[index] == item); // true
sum += item;
});
alert(sum);
forEach是一个基本的数组高阶(higher-order)方法,其语法定义为:
array.forEach(callback[, thisObject])第一个参数我们已经知道了,它是一个拥有3个参数的函数,该函数将应用于数组的每一项。而第二个参数表示上下文对象(context object)或者this值,用于指向回调函数的this引用。这有时会挺有用,比如当我们想使用某个对象的方法作为forEach的处理函数时:
var database = {
users: ["CSSer", "John", "David"],
sendEmail: function (user) {
if (this.isValidUser(user)) { /* 发送消息 */ }
},
isValidUser: function (user) {
/* 验证代码 */
}
};
// 向每个用户发送邮件
database.users.forEach( database.sendEmail, database );
简单分析下,在sendMail函数内部的this指向database对象,并且this.isValidUser指向必须的函数,如果我们不传入第二个参数,this值会被默认指向全局对象(在浏览器中是window)或者在strict模式下指向undefined。
再次强调,只有存在的数组项才会被回调函数处理:
var array = [1, 2, 3, "csser"];
delete array[1];
// 删除项2
alert(array);
// "1,,3,csser"
alert(array.length);
// 数组长度仍然为 4
array.forEach(alert);
// 1, 3 和csser