Js reduce()、Map() 的简单理解

239 阅读3分钟

之前一直写前端的JS,因此很多数据并不需要很复杂的处理,并且处理量也不大,因此并没有关注Js给我们提供的这两个熟悉又陌生的东西。而最近更多的是处理NodeJs后端的数据处理问题,发现这些都是及其好用且实用的,他们能帮你处理很多复杂的数据,并且提高代码的性能。

reduce() :

reduce() 是数组的一个遍历方法,但是他与forEach()、map()不同之处,在于reduce()可以返回遍历整个数组后的叠加的结果。

1. 定义:

array.reduce((pre,cur,index,array) => {}, init)

参数:

  • pre:前一个计算过后的返回值,如果没给init赋值,则pre就是array的第一位数据, 而数组的遍历也从数组的第二位开始,or init
  • cur: 当前的值,就是遍历数组目前引用的值,有init,则为array[0]开始, or array[1]
  • index:当前值的下标,有init,则为0开始, or 1
  • 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异步函数的操作。

  1. 使用await Promise.all() 在很多时候是繁琐的不好用的。
  2. forEach(async () => {})虽然可以在每次循环的回调函数的过程中让 await 函数同步调用,但是在循环遍历之后,并不会等待异步函数返回数据再往下进行,往往导致要处理数据的时候还没有返回结果的情况。
  3. 最简单的for循环可以处理类似await的情况,但是在eslint禁止的行为,虽然目前我也不知道为什么,但是还是要遵守下,哈哈
  4. 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数据,使用Mapget(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中的codecode_nm且一一对应, 而得到的数据分别为

  1. dataArr的数据类型为 =>[[{code,code_nm,...},{code,code_nm,...}],[{code,code_nm,...},{code,code_nm,...},{code,code_nm,...}],[{code,code_nm,...}]]
  2. codeMap的数据类型类似于 => {0:{code1:code_nm1,code2:code_nm2},1:{code1:code_nm1,code2:code_nm2,code3:code_nm3},2:{code1:code_nm1}}
  3. 总结:如果使用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

  • 虽然forEachMap可以直接结合使用,但是findsomefilter等都是无法和Map直接使用的,所以要使用这些方法,需要把Map => Array来使用
  • 因为for 循环eslint 规则中无法 进行多级遍历循环使用,但是有时有需要,在获取我们想要的数据的同时,终止所有的遍历循环,此时又无法使用for of,那我们只能使用findsome来代替了。
const myMap = new Map([
  ["key1", "value1"],
  ["key2", "value2"],
]);
[...myMap].find(([key,value]) => {console.log(key,"=====",value); return key === "key1"}) // key1 ===== value1