對於前端的循環遍歷我們知道有
- 針對js數組的forEach()、map()、filter()、reduce()方法
- 針對js對象的for/in語句(for/in也能遍歷數組,但不推薦)
- 針對jq數組/對象的$.each()方法
在語法和參數上他們有什么不同呢?
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()求和為例,看看各個參數代表着什么
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就是很好的方法
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() {
/* 實現 */
};
}
下面來看看這幾個方法不同的地方
定義:
- forEach() 方法用於調用數組的每個元素,並將元素傳遞給回調函數。
- map() 方法返回一個新數組,數組中的元素為原始數組元素調用函數處理后的值。
map()方法按照原始數組元素順序依次處理元素 - filter() 方法創建一個新的數組,新數組中的元素是通過檢查指定數組中符合條件的所有元素。沒有到沒有符合條件時返回空數組。
- reduce() 方法接收一個函數作為累加器,數組中的每個值(從左到右)開始縮減,最終計算為一個值
| forEach | map | filter | reduce | |
|---|---|---|---|---|
| 操作 | 循環(迭代) | 映射 | 過濾器 | 匯總 |
| 返回值 | undefined | 返回新數組 | 返回新數組 | 返回計算結果total |
| 改變原數組? | 看情況 | 否 | 否 | 否 |
| 檢測空數組? | 不檢測 | 不檢測 | 不檢測 | 不檢測 |
下面來看看這幾個方法在應用中的不同:
1.對當前數組每個元素乘於100
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方法會改變原始數組
