龙空技术网

数组遍历归纳

广漂程序猿DevinRock 147

前言:

现时咱们对“js foreach获取索引”大约比较注意,我们都需要了解一些“js foreach获取索引”的相关知识。那么小编同时在网上收集了一些有关“js foreach获取索引””的相关知识,希望看官们能喜欢,我们快快来了解一下吧!

数组遍历

随着 JS 的不断发展,截至 ES7 规范已经有十多种遍历方法。下面按照功能类似的方法为一组,来介绍数组的常用遍历方法。

for、forEach、for ...of

const list = [1, 2, 3, 4, 5, 6, 7, 8,, 10, 11];for (let i = 0, len = list.length; i < len; i++) {  if (list[i] === 5) {    break; // 1 2 3 4    // continue; // 1 2 3 4 6 7 8 undefined 10 11  }  console.log(list[i]);}for (const item of list) {  if (item === 5) {    break; // 1 2 3 4    // continue; // 1 2 3 4 6 7 8 undefined 10 11  }  console.log(item);}list.forEach((item, index, arr) => {  if (item === 5) return;  console.log(index); // 0 1 2 3 5 6 7 9 10  console.log(item); // 1 2 3 4 6 7 8 9 10});

小结

三者都是基本的由左到右遍历数组forEach 无法跳出循环;for 和 for ..of 可以使用 break 或者 continue 跳过或中断。for ...of 直接访问的是实际元素。for 遍历数组索引,forEach 回调函数参数更丰富,元素、索引、原数组都可以获取。for ...of 与 for 如果数组中存在空元素,同样会执行。

some、every

const list = [  { name: '头部导航', backward: false },  { name: '轮播', backward: true },  { name: '页脚', backward: false },];const someBackward = list.some(item => item.backward);// someBackward: trueconst everyNewest = list.every(item => !item.backward);// everyNewest: false

小结

二者都是用来做数组条件判断的,都是返回一个布尔值二者都可以被中断some 若某一元素满足条件,返回 true,循环中断;所有元素不满足条件,返回 false。every 与 some 相反,若有益元素不满足条件,返回 false,循环中断;所有元素满足条件,返回 true。

filter、map

const list = [{ name: '头部导航', type: 'nav', id: 1 },,{ name: '轮播', type: 'content', id: 2 },{ name: '页脚', type: 'nav', id: 3 },];const resultList = list.filter(item => {  console.log(item);  return item.type === 'nav';});// resultList: [//   { name: '头部导航', type: 'nav', id: 1 },//   { name: '页脚', type: 'nav', id: 3 },// ]const newList = list.map(item => {  console.log(item);  return item.id;});// newList: [1, empty, 2, 3]// list: [//   { name: '头部导航', type: 'nav', id: 1 },//   empty,//   { name: '轮播', type: 'content', id: 2 },//   { name: '页脚', type: 'nav', id: 3 },// ]

小结

二者都是生成一个新数组,都不会改变原数组(不包括遍历对象数组是,在回调函数中操作元素对象)二者都会跳过空元素。有兴趣的同学可以自己打印一下map 会将回调函数的返回值组成一个新数组,数组长度与原数组一致。filter 会将符合回调函数条件的元素组成一个新数组,数组长度与原数组不同。map 生成的新数组元素是可自定义。filter 生成的新数组元素不可自定义,与对应原数组元素一致。

find、findIndex

const list = [{ name: '头部导航', id: 1 },{ name: '轮播', id: 2 },{ name: '页脚', id: 3 },];const result = list.find((item) => item.id === 3);// result: { name: '页脚', id: 3 }result.name = '底部导航';// list: [//   { name: '头部导航', id: 1 },//   { name: '轮播', id: 2 },//   { name: '底部导航', id: 3 },// ]const index = list.findIndex((item) => item.id === 3);// index: 2list[index].name // '底部导航';

小结

二者都是用来查找数组元素。find 方法返回数组中满足 callback 函数的第一个元素的值。如果不存在返回 undefined。findIndex 它返回数组中找到的元素的索引,而不是其值,如果不存在返回 -1。

reduce、reduceRight

reduce 方法接收两个参数,第一个参数是回调函数(callback) ,第二个参数是初始值(initialValue)。

reduceRight 方法除了与reduce执行方向相反外(从右往左),其他完全与其一致。

回调函数接收四个参数:

accumulator:MDN 上解释为累计器,但我觉得不恰当,按我的理解它应该是截至当前元素,之前所有的数组元素被回调函数处理累计的结果。current:当前被执行的数组元素。currentIndex: 当前被执行的数组元素索引。sourceArray:原数组,也就是调用 reduce 方法的数组。

如果不传入初始值,reduce 方法会从索引 1 开始执行回调函数,如果传入初始值,将从索引 0 开始、并从初始值的基础上累计执行回调。

计算对象数组某一属性的总和

const list  = [  { name: 'left', width: 20 },  { name: 'center', width: 70 },  { name: 'right', width: 10 },];const total = list.reduce((currentTotal, item) => {  return currentTotal + item.width;}, 0);// total: 100

对象数组的去重,并统计每一项重复次数

const list  = [  { name: 'left', width: 20 },  { name: 'right', width: 10 },  { name: 'center', width: 70 },  { name: 'right', width: 10 },  { name: 'left', width: 20 },  { name: 'right', width: 10 },];const repeatTime = {};const result = list.reduce((array, item) => {  if (repeatTime[item.name]) {    repeatTime[item.name]++;    return array;  }  repeatTime[item.name] = 1;  return [...array, item];}, []);// repeatTime: { left: 2, right: 3, center: 1 }// result: [//   { name: 'left', width: 20 },//   { name: 'right', width: 10 },//   { name: 'center', width: 70 },// ]

对象数组最大/最小值获取

const list  = [  { name: 'left', width: 20 },  { name: 'right', width: 30 },  { name: 'center', width: 70 },  { name: 'top', width: 40 },  { name: 'bottom', width: 20 },];const max = list.reduce((curItem, item) => {  return curItem.width >= item.width ? curItem : item;});const min = list.reduce((curItem, item) => {  return curItem.width <= item.width ? curItem : item;});// max: { name: "center", width: 70 }// min: { name: "left", width: 20 }

reduce 很强大,更多奇技淫巧推荐查看这篇《25个你不得不知道的数组reduce高级用法》

性能对比

说了这么多,那这些遍历方法, 在性能上有什么差异呢?我们在 Chrome 浏览器中尝试。我采用每个循环执行10次,去除最大、最小值 取平均数,降低误差。

var list = Array(100000).fill(1)console.time('for');for (let index = 0, len = list.length; index < len; index++) {}console.timeEnd('for');// for: 2.427642822265625 msconsole.time('every');list.every(() => { return true })console.timeEnd('every')// some: 2.751708984375 msconsole.time('some');list.some(() => { return false })console.timeEnd('some')// some: 2.786590576171875 msconsole.time('foreach');list.forEach(() => {})console.timeEnd('foreach');// foreach: 3.126708984375 msconsole.time('map');list.map(() => {})console.timeEnd('map');// map: 3.743743896484375 msconsole.time('forof');for (let index of list) {}console.timeEnd('forof')// forof: 6.33380126953125 ms

从打印结果可以看出,for 循环的速度最快,for of 循环最慢

常用遍历的终止、性能表格对比

是否可终止

****

break

continue

return

性能(ms)

for

终止 ✅

跳出本次循环 ✅

2.42

forEach

3.12

map

3.74

for of

终止 ✅

跳出本次循环 ✅

6.33

some

return true ✅

2.78

every

return false ✅

2.75

最后,不同浏览器内核 也会有些差异,有兴趣的同学也可以尝试一下。

标签: #js foreach获取索引