js中数组的循环与遍历forEach,map

对于前端的循环遍历咱们知道有javascript

  • 针对js数组的forEach()、map()、filter()、reduce()方法
  • 针对js对象的for/in语句(for/in也能遍历数组,但不推荐)
  • 针对jq数组/对象的$.each()方法

在语法和参数上他们有什么不一样呢?css

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是怎么循环一个数组的前端

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、map、filter、reduce参数.png


既然他们参数都是同样的,咱们以forEach()求和为例,看看各个参数表明着什么java

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就是很好的方法json

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 的值是 该方法遍历到它们的那一时刻的值;被删除的元素将不会被访问到。例如:数组

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方法:服务器

if (typeof Array.prototype.forEach != "function") {
    Array.prototype.forEach = function() {
        /* 实现 */
    };
}

  


下面来看看这几个方法不一样的地方app

定义:函数

  1. forEach() 方法用于调用数组的每一个元素,并将元素传递给回调函数。
  2. map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
    map()方法按照原始数组元素顺序依次处理元素
  3. filter() 方法建立一个新的数组,新数组中的元素是经过检查指定数组中符合条件的全部元素。没有到没有符合条件时返回空数组。
  4. reduce() 方法接收一个函数做为累加器,数组中的每一个值(从左到右)开始缩减,最终计算为一个值
  forEach map filter reduce
操做 循环(迭代) 映射 过滤器 汇总
返回值 undefined 返回新数组 返回新数组 返回计算结果total
改变原数组? 看状况
检测空数组? 不检测 不检测 不检测 不检测

下面来看看这几个方法在应用中的不一样:
1.对当前数组每一个元素乘于100oop

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.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对象数组中某个属性结合?

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 res3 = [];
arr.forEach(function(v){
  res3.push(v.a);
});
console.log(res3); // [1, 4, 7]


3.map方法
var res2 = arr.map(function(v){
  return v.a
});
console.log(res2);  // [1, 4, 7]



4.for/in语句
var res4 = [];
for(var k in arr){
  res4.push(k);
};
console.log(res4);  // ["0", "1", "2"]
//for in 本来是遍历对象的,k为属性的键,因此k在这里为数组的下标。应改为以下
console.log('-----------------------');

var res5 = [];
for(k in arr){
     res5.push(arr[k].a)
};
console.log(res5);  //[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()对数组的每一个元素进行必定的操做(映射)后,会返回一个新的数组;是处理服务器返回信息很是有用的函数。

  • 求数组中每一个元素的平方↓
只有一个参数来mapping一个数字数组
var res = [1,4,9].map(function(val){
    return val*2   //[2,8,18]
});

  

  • 求数组中每一个元素的平方根↓
var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
//roots的值为[1, 2, 3]
//numbers的值仍为[1, 4, 9]

  

  • 使用map获取json数组中的某个属性集合
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从新格式化对象数组中的对象↓
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的所有元素

[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方法主要是对数组的筛选过滤,返回符合条件的元素,
例如,
------ 对于数组

// 筛选出大于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’属性值的对象

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"格式

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方法会改变原始数组