之前一直写前端的JS,因此很多数据并不需要很复杂的处理,并且处理量也不大,因此并没有关注Js给我们提供的这两个熟悉又陌生的东西。而最近更多的是处理NodeJs后端的数据处理问题,发现这些都是及其好用且实用的,他们能帮你处理很多复杂的数据,并且提高代码的性能。
reduce() :
reduce() 是数组的一个遍历方法,但是他与forEach()、map()不同之处,在于reduce()可以返回遍历整个数组后的叠加的结果。
1. 定义:
array.reduce((pre,cur,index,array) => {}, init)
参数:
- pre:前一个计算过后的返回值,如果没给
init赋值,则pre就是array的第一位数据, 而数组的遍历也从数组的第二位开始,orinit - cur: 当前的值,就是遍历数组目前引用的值,有
init,则为array[0]开始, orarray[1] - index:当前值的下标,有
init,则为0开始, or1 - array: 遍历数组的本身
array - init: 初始值,如果想要数组从第一位开始遍历,那么
init不能为空。
2. 简单应用:
处理一些小学问题,例如1加到n。
const sumNum = (n) => {
let numArr = [];
let i = 0;
while(i <= n) {
numArr.push(i);
i++;
}
return numArr.reduce((pre,cur) => pre + cur, 0);
}
console.log(sumNum(100));
与async await结合使用
nodeJS在处理后端数据的时候,经常遇到循环处理一些async异步函数的操作。
- 使用
await Promise.all()在很多时候是繁琐的不好用的。forEach(async () => {})虽然可以在每次循环的回调函数的过程中让await 函数同步调用,但是在循环遍历之后,并不会等待异步函数返回数据再往下进行,往往导致要处理数据的时候还没有返回结果的情况。- 最简单的
for循环可以处理类似await的情况,但是在eslint禁止的行为,虽然目前我也不知道为什么,但是还是要遵守下,哈哈- 而
reduce()每次遍历调用回调函数,都需要得到上一次的回调pre值, 因为这个特点,则导致 reduce() 可以完美解决这个问题。
- 示例如下:
const params = [{type:'A',lang:'EN'},{type:'B',lang:'EN'},{type:'C',lang:'EN'}];
let dataArr = [];
await params.reduce(async(pre,cur) => {
await pre;
const {type,lang} = cur;
const dataList = await Query.selectDataList(knex,{type,lang});
dataArr.push(dataList);
return Promise.resolve();
},Promise.resolve());
这样可以直接获取所有的
dataList, 如果使用Promise.all(),则在循环之后,还要再处理数据,如果每个dataList数组中还需要进一步进行数据处理,那就就比较繁琐了。
Map():
new Map()是ES6 创建的一个数据类型,与new Object()类似 , 但是Map的创建方式比较Object要简洁一些,且Map可以使用任何数据类型为Key值,最重要的是Map的添加方式是有顺序的,而Object是无序的。 使用Map的优势:把一些复杂嵌套数组[[...],[...],...]处理成Map数据,使用Map的get(key)方法,可以避免没必要的循环遍历,进而提高代码的运行效率。
1. 简单应用: (与reduce()结合使用)
const params = [{type:'A',lang:'EN'},{type:'B',lang:'EN'},{type:'C',lang:'EN'}];
let dataArr = [];
const codeMap = new Map();
await params.reduce(async(pre,cur,index) => {
await pre;
const {type,lang} = cur;
const dataList = await Query.selectDataList(knex,{type,lang});
dataArr.push(dataList);
codeMap.set(index,new Map(dataList.map(d => [d.code,d.code_nm])))
return Promise.resolve();
},Promise.resolve());
假定我们只需要
dataList中的code和code_nm且一一对应, 而得到的数据分别为
dataArr的数据类型为 =>[[{code,code_nm,...},{code,code_nm,...}],[{code,code_nm,...},{code,code_nm,...},{code,code_nm,...}],[{code,code_nm,...}]]codeMap的数据类型类似于 =>{0:{code1:code_nm1,code2:code_nm2},1:{code1:code_nm1,code2:code_nm2,code3:code_nm3},2:{code1:code_nm1}}- 总结:如果使用
dataArr,获取某个数据至少需要遍历两遍,而使用codeMap,需要获取某个数据,例如2里面的code_nm1,则使用codeMap.get(2).get(code1)即可,并且这只是二维数组,如果数据是多维数组,谁的效率更高,高下立判。
2. Map与Object的互转
// Object => Map
let obj1 = {
a: 1,
b: 2
};
let map1 = new Map(Object.entries(obj1));
console.log( map1.get('a') ); // 1
//Map => Object
let map2 = new Map([
["a", 1],
["b", 2],
]);
let obj2 = Object.fromEntries(map2.entries());
console.log(obj2.b); //2
3. Map 与 Array的互转
// Array => Map
const myMap = new Map([
["key1", "value1"],
["key2", "value2"],
]);
// Map => Array
const myArray = Array.from(myMap); // or [...myMap]
// keys
[...myMap.keys()]; // => ["key1","key2"]
// values
[...myMap.values()]; // => ["value1", "value2"]
4. 遍历Map
const myMap = new Map([
["key1", "value1"],
["key2", "value2"],
]);
myMap.forEach((value,key) => {console.log(key, "=====", value)}); // key1 ===== value1, key2 ===== value2
for (const [key, value] of myMap) { console.log(key, "=====", value) }; // key1 ===== value1, key2 ===== value2
for (const [key, value] of myMap.entries()) { console.log(key, "=====", value) }; // key1 ===== value1, key2 ===== value2
for (const key of myMap.keys()) { console.log(key, "=====") }// key1 =====, key2 =====
for (const value of myMap.values()) { console.log("=====", value) }// ===== value1, ===== value2
- 虽然
forEach和Map可以直接结合使用,但是find,some,filter等都是无法和Map直接使用的,所以要使用这些方法,需要把Map => Array来使用 - 因为
for 循环在eslint 规则中无法 进行多级遍历循环使用,但是有时有需要,在获取我们想要的数据的同时,终止所有的遍历循环,此时又无法使用for of,那我们只能使用find和some来代替了。
const myMap = new Map([
["key1", "value1"],
["key2", "value2"],
]);
[...myMap].find(([key,value]) => {console.log(key,"=====",value); return key === "key1"}) // key1 ===== value1