Array.prototype.forEach()
forEach()
方法对数组的每个元素执行一次给定的函数。函数返回值为undefined
语法:
arr.forEach(callback(currentValue [, index [, array]]) [, thisArg])
(1)forEach()
方法有效值
按升序为数组中含有效值的每一项执行一次 callback
函数,那些已删除或者未初始化的项将被跳过
(例如在稀疏数组上,new Array(7) 得到 [empty × 7],Array.of(7)得到[7])。
(2)数组forEach内函数的this指向
foreEach方法的第二个参数thisArg
ES5 :如果第二个参数thisArg是对象,this指向该对象;如果是undefined或者null,this指向window。——除非指定了this对象,不然函数的this指向window。(ES5中函数this的特性)
严格模式下,如果指定了对象,那么this指向该对象,否则this为undefined。除非指定了对象,不然this指向undefined——严格模式this的特性
ES6箭头函数:继承外层普通函数的this,——箭头函数特性
(3)关于修改原数组:
删除原数组某项时,以下示例:操作b这项时,处理函数中 index是1,item是b;移除了arr中b元素。导致arr为['a','c','d'],接下来index执行2。
所以打印结果:a b d
var obj = {
name: 'obj'
};
var arr = ['a','b','c','d'];
arr.forEach(function(item, index, arr){
if(index == 1){//操作b这项数据时,index是1,item是b;移除了arr中的b元素
arr.shift();
}
console.log(item);
},obj)
移除项同时添加项:结果a b d e
var obj = {
name: 'obj'
};
var arr = ['a','b','c','d'];
arr.forEach(function(item, index, arr){
if(index == 1){//操作b这项数据时,index是1,item是b;移除了arr中的b元素
arr.shift();
arr.push('e','f')
}
console.log(item);
},obj)
下面示例重要
由原数组确定了index值,先判断该index对应item是否有效,无效跳过该item。index的值最开始被确定好,每当函数执行时,index对应数组最新的元素,判断该元素是否有效(empty,delete的项,数组长度变化导致index传入后无该项)
如下:forEach遍历index值被确定,
var arr = ['a',,'b','c']
var i=100
arr.forEach(item => {
console.log(item)// a b c
if(i < 105){
arr.push(i++)
}
})
arr //["a", empty, "b", "c", 100, 101, 102]
如果数据中有空项(稀疏数组)
var arr = [10,20,,30,40];
arr.forEach((item, index, originArr) => {
console.log(index); //0 1 3 4
})
var arr = [10,20,,30,40];
arr.forEach((item, index, originArr) => {
console.log(index); //0 1 2 3
if(index == 1){
originArr.shift();
}
})
forEach修改元素组总结:
forEach()
遍历的范围在第一次调用 callback
前就会确定。——会计算好有效遍历范围index值的范围,比如 :[1,2,,3,4]遍历index值到4,如果原数组未改变,index值为2时,值最多遍历四次。
在确定遍历index范围后,每次遍历根据index索引值查找数组中最新的item值——上述两个例子也能体现 。
原数组的长度length确定了index值可以走到哪里,比如上述第三个示例,长度为5,意味着index可以走
forEach不可中止或跳出遍历:
除了抛出异常以外,没有办法中止或跳出 forEach()
循环。如果你需要中止或跳出循环,forEach()
方法不是应当使用的工具。
数组方法具有中止遍历的有:some、every、finde、findIndex
for、for in、for of可以通过break continue中止或跳出
forEach地址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
示例:
扁平化数组:
var result = [];
function flatten(arr){
arr.forEach((item, index) =>{
if(Array.isArray(item)){
arguments.callee(item)
}else{
result.push(item);
}
})
}
const problem = [1, 2, 3, [4, 5, [6, 7], 8, 9]];
flatten(problem)
console.log(result) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
拓展其他数组方法:
forEach、map、filter、some、every:都是同样的参数,处理函数具有相同的处理效果,ES6又补充了find、findIndex方法
(1)这些方法都不会改变原数组
(2)空数组不会调用处理函数,且每个方法返回自己期望的类型值。比如some方法,如果用一个空数组进行测试,在任何情况下它返回的都是false
。
forEach方法:没有返回值,或者说返回值是undefined,该方法的目的是处理数组中的每项,而不考虑返回值。
map方法:返回值是该数组中的每个元素是调用一次提供的函数后的返回值组成的数组 。map期望处理函数都有返回值,当你不打算使用返回的新数组却使用map
是违背设计初衷的,请用forEach或for of代替。
稍微注意一下:map遇到empty值时,处理函数的执行也是index值对应item有效才会进行函数处理。无效就跳过,处理下一个。
对于map而言,push这些值进入数组后,就会构成如下面打印值一样的情况。
0: "a"
1: "b"
3: "c"
4: "d"
length: 5
var arr = ['a','b',,'c','d']
var arr1 = arr.map(function(item, index){
console.log(index)//执行四次
return item;
})
console.log(arr1); //["a", "b", empty, "c", "d"]
var arr2 = arr.forEach(function(item, index){
console.log(index)//执行四次
})
filter方法:返回处理结果为 true 的项组成的数组,filter方法的目的是通过原数组过滤出一个期望的新数组 。
some方法:返回的是一个Boolean类型的值,some方法测试数组中是不是至少有1个元素符合处理函数期望 。
every方法:返回一个布尔值,测试一个数组内的所有元素是否都能通过某个指定函数的测试。注意:若收到一个空数组,此方法在一切情况下都会返回 true
。
理解:some默认返回值为false,找到一个true ,结果就为true。every方法默认为true,遇到一个假,结果就false。
find() 方法返回数组中满足提供的测试函数的第一个元素的值,否则返回undefined。
findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1。
find和findIndex与ES5的5个方法在处理函数方面有点区别:
index范围确定后,ES5的5个方法是根据index判断最新对应item是否合法,合法才会进行处理。而find和findIndex方法,是根据index值来判断是否合法,所以下面示例的结果是:10 20 30 40 undefined
var arr = [10,20,,30,40];
arr.find((item, index, originArr) => {
console.log(item)
if(index==1){
arr.shift();
}
})