js中数组的循环与遍历forEach,map
对于前端的循环遍历我们知道有
- 针对js数组的forEach()、map()、filter()、reduce()方法
- 针对js对象的for/in语句(for/in也能遍历数组,但不推荐)
- 针对jq数组/对象的$.each()方法
在语法和参数上他们有什么不同呢?
1 2 3 4 5 6 | 1.forEach: array.forEach(function(currentValue,index,arr), thisValue) 2.map: array.map(function(currentValue,index,arr), thisValue) 3.filter: array.filter(function(currentValue,index,arr), thisValue) 4.reduce: array.reduce(function(total,currentValue,index,arr), thisValue) 5.$.each: $.each( object /array, function(index,elment) ); //jQuery的遍历方法,这里先不多说 6. for / in : for ( var key in object ) { //... } |
这些方法都是源于for的封装而来的,先来看看for是怎么循环一个数组的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | var arr = [4,3,2,1]; var index = []; var value = []; var sum = 0; for ( var i=0;i<arr.length;i++){ index.push(i); value.push(arr[i]) sum += arr[i] }; console.log(index); //[0, 1, 2, 3] console.log(value); // [4,3,2,1] console.log(sum); //10 //可以看出,i表示的是数组下标,arr[i]是通过下标来去的对应的值 |
forEach、map、filter、reduce方法相同点
**参数

既然他们参数都是一样的,我们以forEach()求和为例,看看各个参数代表着什么
1 2 3 4 5 6 7 8 9 10 | var arr = [4,3,2,1]; var sum = 0; arr.forEach(function(val,index,arr){ console.log(val); //4 console.log(index); //0 console.log(arr); //[4,3,2,1] console.log(arr[index]==val); // ==> true sum+=val }); console.log(sum); //10 |
从上可得,这几个方法中参数所代表的都是相同的。
关于参数还有一个点没说的是,reduce方法还有个参数,语法如下:
array.reduce(function(total, currentValue, index, arr), initialValue)
其中 currentValue, index, arr意义相同,而total代表计算的初始值, 也是计算结束后的返回值。
其中total, currentValue都是必须的参数。
对于计算一个数组的和,reduce就是很好的方法
1 2 3 4 5 | var arr = [ 4 , 3 , 2.1 , 1.1 ]; var sum = arr.reduce(function(total, val) { return total + Math.round(val); }); console.log(sum);// 10 |
**迭代时不做修改
这些方法处理数组时,数组元素的范围是在 callback 方法第一次调用之前就已经确定了。;若已经存在的元素被改变或删除了,则它们的传递到 callback 的值是 该方法遍历到它们的那一时刻的值;被删除的元素将不会被访问到。例如:
1 2 3 4 5 6 7 8 | var words = [ "one" , "two" , "three" , "four" ]; words.forEach(function(word) { console.log(word); if (word === "two" ) { words.shift(); } }); console.log(words);//[ "two" , "three" , "four" ] |
**兼容旧环境
这些方法都是ECMA5新增的数组方法,所以ie9以下都不支持,不过,可以从Array原型拓展从而实现以上全部功能,例如forEach方法:
1 2 3 4 5 | if (typeof Array.prototype.forEach != "function" ) { Array.prototype.forEach = function() { /* 实现 */ }; } |
下面来看看这几个方法不同的地方
定义:
- forEach() forEach循环,循环数组中每一个元素并采取操作, 没有返回值, 可以不用知道数组长度
- map函数,遍历数组每个元素,并回调操作,需要返回值,返回值组成新的数组,原数组不变
- filter() 过滤通过条件的元素组成一个新数组, 原数组不变
- reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值
- some函数,遍历数组中是否有符合条件的元素,返回Boolean值
forEach | map | filter | reduce | |
---|---|---|---|---|
操作 | 循环(迭代) | 映射 | 过滤器 | 汇总 |
返回值 | undefined | 返回新数组 | 返回新数组 | 返回计算结果total |
改变原数组? | 看情况 | 否 | 否 | 否 |
检测空数组? | 不检测 | 不检测 | 不检测 | 不检测 |
下面来看看这几个方法在应用中的不同:
1.对当前数组每个元素乘于100
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 1 .for方法 var b = [ 1 , 2 , 3 ]; var f = []; for(var i= 0 ;i<b.length;i++){ f.push(b[i]* 100 ) }; console.log(f); //[ 100 , 200 , 300 ] 2 .forEach方法: var b = [ 1 , 2 , 3 ]; var f = [] b.forEach(function(v){ f.push(v* 100 ) }); console.log(f); //[ 100 , 200 , 300 ] console.log(b); // [ 1 , 2 , 3 ] 2 . forEach方法: var b = [ 1 , 2 , 3 ]; b.forEach(function(item,index,arr){ arr[index] = item* 100 ; }); console.log(b); //[ 100 , 200 , 300 ] 3 .map方法: var b = [ 1 , 2 , 3 ]; var c = b.map(function(v){ return v* 100 } ) console.log(c); //[ 100 , 200 , 300 ] 4 .for/in语句 var b = [ 1 , 2 , 3 ]; var f = []; for(var k in b){ f.push(b[k]* 100 ) } console.log(f); //[ 100 , 200 , 300 ] |
2.对数组的求和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 1 .for循环 var arr = [ 1 , 2 , 3 , 4 , 5 ]; var sum = 0 ; //这里sum设置为 0 或null for(i= 0 ;i<arr.length;i++){ sum += arr[i]; }; console.log(sum);// 15 2 .forEach方法 var arr = [ 1 , 2 , 3 , 4 , 5 ]; var sum = 0 ; arr.forEach(function(v){ sum += v }) console.log(sum);// 15 3 .map方法 //map不适合用来做和,因为他是对每个元素进行处理,再返回每个元素 4 .for/in语句 var arr = [ 1 , 2 , 3 , 4 , 5 ]; var sum = 0 ; for(var k in arr){ sum += arr[k] }; console.log(sum); // 15 |
3.js如何获取json对象数组中某个属性结合?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | var arr = [ {a: 1 ,b: 2 ,c: 3 }, {a: 4 ,b: 5 ,c: 6 }, {a: 7 ,b: 8 ,c: 9 } ]; 获取数组arr的a属性集合,有哪些方法? 1 .for循环 var res = []; for(var i= 0 ;i<arr.length;i++){ res.push(arr[i].a) }; console.log(res); // [ 1 , 4 , 7 ] 2 .forEach方法 var res 3 = []; arr.forEach(function(v){ res 3 .push(v.a); }); console.log(res 3 ); // [ 1 , 4 , 7 ] 3 .map方法 var res 2 = arr.map(function(v){ return v.a }); console.log(res 2 ); // [ 1 , 4 , 7 ] 4 .for/in语句 var res 4 = []; for(var k in arr){ res 4 .push(k); }; console.log(res 4 ); // [ "0" , "1" , "2" ] //for in 原本是遍历对象的,k为属性的键,所以k在这里为数组的下标。应改成如下 console.log( '-----------------------' ); var res 5 = []; for(k in arr){ res 5 .push(arr[k].a) }; console.log(res 5 ); //[ 1 , 4 , 7 ] |
4.给json对象数组中的每个对象多加个字段
var users = [ { lastName: 'Li', firstName: 'Lei' }, { lastName: 'Han', firstName: 'Meimei' } ]; 给其中每一个对象加一个fullName字段,就把lastName和firstName 1.for循环 for(var i = 0; i < users.length; i++){ var user = users[i]; user.fullName = user.lastName + user.firstName; } 代码是对的,但却不好(优秀),为什么?原因有2 创建了与主业务无关的for loop 创建了与主业务无关的变量i 用forEach的好处是什么?答案就是解决了上面那2个缺陷,代码如下: 2.forEach方法 users.forEach(function(user, index, arr){ user.fullName = user.lastName + user.firstName; }); 3.map方法 var newUsers = users.map(function(v,i,arr){ v.fullName = v.lastName+v.firstName; return v }); //主要如果这里return v.fullName = v.lastName+v.firstName;的话,得到的是["LiLei", "HanMeimei"] //注意: 此处的map会改变原始数组,因为给v多加了个属性v.fullName
从上我们可以看出,forEach,for/in,map都是封装了for循环,只是在应用的对象上稍有些不同,例如,
forEach主要数组的一些简单遍历
map主要是对数内每个元素的操作
for/in主要是对象键值的一些遍历
应用与细节
forEach方法
forEach的应用只要是数组的简单遍历,这里就不在多做阐述
map方法
map()对数组的每个元素进行一定的操作(映射)后,会返回一个新的数组;是处理服务器返回信息非常有用的函数。
- 求数组中每个元素的平方↓
1 2 3 4 | 只有一个参数来mapping一个数字数组 var res = [ 1 , 4 , 9 ].map(function(val){ return val* 2 //[ 2 , 8 , 18 ] }); |
- 求数组中每个元素的平方根↓
1 2 3 4 | var numbers = [ 1 , 4 , 9 ]; var roots = numbers.map(Math.sqrt); //roots的值为[ 1 , 2 , 3 ] //numbers的值仍为[ 1 , 4 , 9 ] |
- 使用map获取json数组中的某个属性集合
1 2 3 4 5 6 7 8 9 10 | var users = [ {name: 'zhou' ,email: 'zhou@email.com' }, {name: 'lin' ,email: 'lin@email.com' }, {name: 'wu' ,email: 'wu@email.com' } ]; var emails = users.map(function(v){ return v.email }); console.log(emails) // [ "zhou@email.com" , "lin@email.com" , "wu@email.com" ] |
- 使用map重新格式化对象数组中的对象↓
1 2 3 4 5 6 7 8 9 10 11 12 13 | var arr= [ {key: 1, value: 10}, {key: 2, value: 20}, {key: 3, value: 30} ]; var reformattedArray = arr.map( function (obj) { var rObj = {}; rObj[obj.key] = obj.value; return rObj; //[{1: 10}, {2: 20}, {3: 30}] }); //注意: 这里是 return rObj整个对象, 如果是 return rObj[obj.key] = obj.value; 值为[10,20,30] |
可以看出以上map()的用法都是对集合里的每个元素做对应的实际的操作后,再返回到新的数组里。那如何使只对集合的某些元素做判断呢?返回的是什么,如下面例子:
在数组中取大于3的全部元素
1 2 3 4 5 6 7 | [2, 3, 4, 5].map( function (val, key) { return val > 3; //[false, false, true, true] }) [2, 3, 4, 5].map( function (val, key) { if (val > 3){ return val} //[undefined, undefined, 4, 5] }) |
上面的结果都不是我们想要的,我们想要的只是纯粹的大于3的集合[4,5],对集合的每个元素进行判断,刷选出符合条件的元素,该怎么做呢?filter就是专为这种处理而生的。
filter方法
filter方法主要是对数组的筛选过滤,返回符合条件的元素,
例如,
------ 对于数组
1 2 3 4 5 6 7 8 9 | // 筛选出大于3的数 [2, 3, 4, 5,10].filter( function (val, index) { return val > 3; //[4,5] }) // 筛选出能整除5的数 [2, 3, 4, 5,10].filter( function (val, index) { return val % 5 == 0; //[5,10] }) |
----- 对于json数组
筛选对象数组中含有‘orange’属性值的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | var arr = [ { "name" : "apple" , "count" : 2}, { "name" : "orange" , "count" : 5}, { "name" : "pear" , "count" : 3}, { "name" : "orange" , "count" : 16}, ]; 1.filter方法 var newArr = arr.filter( function (item){ return item.name === "orange" ; }); console.log(newArr); // [{ "name" : "orange" , "count" : 5}, { "name" : "orange" , "count" : 16}] 2.forEach方法 var newArr2 = []; arr.forEach( function (v){ if (v.name === 'orange' ){ newArr2.push(v) } }); console.log(newArr2); // [{ "name" : "orange" , "count" : 5}, { "name" : "orange" , "count" : 16}] 4. for 循环 var newArr4 = []; for ( var i= 0, l = arr.length; i< l; i++){ if (arr[i].name === "orange" ){ newArr4.push(arr[i]); } } console.log(newArr4); // [{ "name" : "orange" , "count" : 5}, { "name" : "orange" , "count" : 16}] 3.map方法 var newArr3 = arr.map( function (item){ return item.name === "orange" ; }); console.log(newArr3); //[false, true, false, true] Console.log(‘-------------------------------’) var newArr3 = arr.map( function (v){ if (v.name === 'orange' ){ return v } }); console.log(newArr3) // [ undefined, { "name" : "orange" , "count" : 5}, { "name" : "orange" , "count" : 16}, undefined ] |
reduce方法
(暂时还不大理解,暂不做解释,哈哈哈哈哈哈哈哈)
请移步到 js中的reduce()函数
上面的分析和举例,同一种功能不同方法的实现,主要是为了让大家理解每个方法的实现的内在原理(for循环),被封装后有什么差异,比如不同参数的值,返回结果,以便在以后的实际应用中能根据业务需求用更简便合适的方法来实现。
根据实际需求做合适的数据处理
有一组成绩,需做一些操作:
1 输出全部考生名字
1 成绩大于60记为及格,否则不及格
2 过滤出成绩大于60的数据
3 计算出总成绩
4 输出:"姓名:xx 成绩:1xx"格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | var grades= [ {name: "优优" , grade: 92}, {name: "小渣" , grade: 55}, {name: "小优" , grade: 82} ] grades.map(v => v.name) // ["优优", "小渣", "小优"] grades.map(v => v.grade > 60 ? '及格' : '不及格' ) // ["及格", "不及格", "及格"] grades.filter(v => v.grade > 60) // [{name: "优优", grade: 92}, {name: "小优", grade: 82}] grades.reduce((total, v, i, arr) => { return total + v.grade },0) //229 grades.forEach((v, i, arr) => { v.all = `姓名:${v.name}, 成绩:${v.grade}` }); console.log(grades) //[{name: "优优", grade: 92, all: "姓名:优优, 成绩:92"}, //{name: "小渣", grade: 55, all: "姓名:小渣, 成绩:55"}, //{name: "小优", grade: 82, all: "姓名:小优, 成绩:82"}] //forEach方法会改变原始数组 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通