forEach
map
var arr=[1,2,3,4,5];
function forEach(fn){
for(var i=0;i<arr.length;i++){
//调用
fn(arr[i],i,arr);
}
}
function callBack(item,index,arr){
//这是我自己写的回调函数
console.log(item);
}
forEach(callBack);
类似于:
forEach(function(item,index,arr){
console.log(item);
});
这里是匿名函数。
所以这里没有区别,就直接传递
map
var arr=[];
function map(fn){
var arr1=[];
for(var i=0;i<arr.length;i++){
if(i in arr){
var item = fn(arr[i],i,arr);
arr1[i] = item;
}
}
return arr1;
}
function callBack(item,index,arr){
//这是我自己写的回调函数
console.log(item);
//返回什么完全凭自己喜好
return item;
}
map(callBack);
类似于:
map(function(item,index,arr){
console.log(item);
return item;
});
这里是匿名函数。
所以这里没有区别,就直接传递
1.map是浅拷贝。
2.map,forEach自动忽略空值。
我理解大多数人迫切想要在forEach里加break;的决心。
那就用for他不香么?
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
for (var i = 0; i < arr.length;) {
if (arr[i] % 2 === 0 && arr[i] % 3 === 0) {
arr.splice(i, 1);
continue;
}
i++
}
arr.forEach(function (item, index) {
console.log(item);
if (item % 2 === 0 && item % 3 === 0) {
//错误啊,唉
arr.splice(index, 1);
}
});
console.log(arr);
方法1
arr.forEach(function (item, index, array) {
if (item % 2 === 0 && item % 3 === 0) {
arr.splice(index, 1);
//错误,[6,12,6,6,6,12] 12删除不了
var i;
while ((i = array.indexOf(item)) !== -1) {
arr.splice(i, 1);
}
}
});
方法2
arr.forEach(function (item, index, array) {
if (item % 2 === 0 && item % 3 === 0) {
arr.splice(index, 1);
//错误,index是函数内部的局部变量,是复制而不是地址,
//所以改变不了增强for循环里面的i。
index--;
}
});
教训和总结
forEach()就是单纯的遍历,且因为for有i++必须执行的条件,(即使加了continue,break不行),所以你没办法改变系统forEach中i的值。forEach就是会忠诚地执行这个循环直到数组结束,期间你删除了一个元素,那你就错过了下一个元素。因为下一个元素的索引变成了本轮的这个元素的索引。而且用forEach你没办法清楚这个数组,假设你是用pop()删的,你每次删后,你的长度就减少。但是你删的是最后1个,但是你已经从左到右走到下一个了,那么你走过的那个就永远不会被删除。
简而言之,forEach这种封装很好的执行了桥接模式,我就是干遍历这么一件事。你不管回调函数里怎么搞,都不会影响我的实现。即使我给你了arr这个指针,你可能对我改变,但由于我不等人的特性,你改变了只会增加你的复杂度,到头来还是不会用我forEach,所以,函数式编程的思想真的很神奇。