JS中数组常用的循环遍历你会几种

前言

数组和对象作为一个最基础数据结构,在各种编程语言中都充当着至关重要的角色,你很难想象没有数组和对象的编程语言会是什么模样,特别是 JS ,弱类型语言,非常灵活。本文带你了解常用数组遍历、对象遍历的使用对比以及注意事项。

数组遍历

随着 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: true
const 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: 2
list[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 ms

console.time('every');
list.every(() => { return true })
console.timeEnd('every')
// some: 2.751708984375 ms

console.time('some');
list.some(() => { return false })
console.timeEnd('some')
// some: 2.786590576171875 ms

console.time('foreach');
list.forEach(() => {})
console.timeEnd('foreach');
// foreach: 3.126708984375 ms

console.time('map');
list.map(() => {})
console.timeEnd('map');
// map: 3.743743896484375 ms

console.time('forof');
for (let index of list) {
}
console.timeEnd('forof')
// forof: 6.33380126953125 ms

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

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

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

对象遍历

在对象遍历中,经常需要遍历对象的键、值,ES5 提供了 for...in 用来遍历对象,然而其涉及对象属性的“可枚举属性”、原型链属性等,下面将从 Object 对象本质探寻各种遍历对象的方法,并区分常用方法的一些特点。

for in

Object.prototype.fun = () => {};
const obj = { 2: 'a', 1: 'b' };
for (const i in obj) {
  console.log(i, ':', obj[i]);
}
// 1: b
// 2: a
// fun : () => {} Object 原型链上扩展的方法也被遍历出来
for (const i in obj) {
  if (Object.prototype.hasOwnProperty.call(obj, i)) {
      console.log(i, ':', obj[i]);
    }
}
// name : a 不属于自身的属性将被 hasOwnProperty 过滤

小结

使用 for in 循环时,返回的是所有能够通过对象访问的、可枚举的属性,既包括存在于实例中的属性,也包括存在于原型中的实例。如果只需要获取对象的实例属性,可以使用 hasOwnProperty 进行过滤。

使用时,要使用(const x in a)而不是(x in a)后者将会创建一个全局变量。

for in 的循环顺序,参考【JavaScript 权威指南】(第七版)6.6.1。

  • 先列出名字为非负整数的字符串属性,按照数值顺序从最小到最大。这条规则意味着数组和类数组对象的属性会按照顺序被枚举。
  • 在列出类数组索引的所有属性之后,在列出所有剩下的字符串名字(包括看起来像整负数或浮点数的名字)的属性。这些属性按照它们添加到对象的先后顺序列出。对于在对象字面量中定义的属性,按照他们在字面量中出现的顺序列出。
  • 最后,名字为符号对象的属性按照它们添加到对象的先后顺序列出。

Object.keys

Object.prototype.fun = () => {};
const str = 'ab';
console.log(Object.keys(str));
// ['0', '1']
const arr = ['a', 'b'];
console.log(Object.keys(arr));
// ['0', '1']
const obj = { 1: 'b', 0: 'a' };
console.log(Object.keys(obj));
// ['0', '1']

小结

用于获取对象自身所有的可枚举的属性值,但不包括原型中的属性,然后返回一个由属性名组成的数组。

Object.values

Object.prototype.fun = () => {};
const str = 'ab';
console.log(Object.values(str));
// ['a', 'b']
const arr = ['a', 'b'];
console.log(Object.values(arr));
// ['a', 'b']
const obj = { 1: 'b', 0: 'a' };
console.log(Object.values(obj));
// ['a', 'b']

小结

用于获取对象自身所有的可枚举的属性值,但不包括原型中的属性,然后返回一个由属性值组成的数组。

Object.entries

const str = 'ab';
for (const [key, value] of Object.entries(str)) {
    console.log(`${key}: ${value}`);
}
// 0: a
// 1: b
const arr = ['a', 'b'];
for (const [key, value] of Object.entries(arr)) {
    console.log(`${key}: ${value}`);
}
// 0: a
// 1: b
const obj = { 1: 'b', 0: 'a' };
for (const [key, value] of Object.entries(obj)) {
    console.log(`${key}: ${value}`);
}
// 0: a
// 1: b

小结

用于获取对象自身所有的可枚举的属性值,但不包括原型中的属性,然后返回二维数组。每一个子数组由对象的属性名、属性值组成。可以同时拿到属性名与属性值的方法。

Object.getOwnPropertyNames

Object.prototype.fun = () => {};
Array.prototype.fun = () => {};
const str = 'ab';
console.log(Object.getOwnPropertyNames(str));
// ['0', '1', 'length']
const arr = ['a', 'b'];
console.log(Object.getOwnPropertyNames(arr));
// ['0', '1', 'length']
const obj = { 1: 'b', 0: 'a' };
console.log(Object.getOwnPropertyNames(obj));
// ['0', '1']

小结

用于获取对象自身所有的可枚举的属性值,但不包括原型中的属性,然后返回一个由属性名组成的数组。

总结

我们对比了多种常用遍历的方法的差异,在了解了这些之后,我们在使用的时候需要好好思考一下,就能知道那个方法是最合适的。欢迎大家纠正补充。

到此这篇关于JS中数组常用的循环遍历的文章就介绍到这了,更多相关JS数组循环遍历内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2021-05-29

javascript 实例详解循环用法

闲来无聊,整理了几道有关循环的简单练习题,希望对初学JS的小伙伴有所帮助. 1.打印1-100之间所有7的倍数的个数及总和 var sum=0; var n=0; for(var i=1;i<=100;i++){ if(i%7==0){ sum+=i; ++n; } } console.log("个数为:"+n+",总和为:"+sum); 运行结果: 2.假设投资的年利率为5%,从1000增到5000需要多少年? var money=1000; var i=0

JavaScript实现循环轮播图

本文实例为大家分享了JavaScript实现循环轮播图的具体代码,供大家参考,具体内容如下 案例演示: 1.点击下面图标,图片进行轮播 2.图片轮播完,接着轮播到第一张 (代码内部具有详细解释) 项目结构图: HTML代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>图片轮播示例</title> <link rel="

详细谈谈JavaScript中循环之间的差异

目录 前言 可枚举的属性 可迭代对象 在 forEach 与 map 方法 链式调用 性能 结论 前言 在 JavaScript 中使用循环时,需要正确定义两个关键内容:可枚举属性(enumerable properties)和可迭代对象(iterable objects). 可枚举的属性 可枚举对象的一个定义特征是,当我们通过赋值运算符将属性赋值给对象时,我们将内部可枚举标志(enumerable)设置为 true.这是默认值. 但是,我们可以通过将其设置为 false 来更改此行为. 经验法

关于js的事件循环机制剖析

前言 众所周知, JavaScript是单线程这一核心,可是浏览器又能很好的处理异步请求,那么到底是为什么呢?其中的原理与事件循环机制大有关系. 在探索事件循环之前,我们得先了解浏览器执行线程~~ 浏览器的渲染进程是多线程的,浏览器每一个tab标签都代表一个独立的进程,其中浏览器内核属于浏览器多进程中的一种,主要负责页面渲染,脚本执行,事件处理等.其包含的线程有以下几种 GUI 渲染线程:负责渲染页面,解析 HTML,CSS 构成 DOM 树: JS 引擎线程:解释执行代码.用户输入和网络请求:

详解JS中你不知道的各种循环测速

前言 在测试循环速度之前,我们先来创建一个有 100 万数据的数组: const len = 100 * 10000; const arr = []; for (let i = 0; i < len; i++) { arr.push(Math.floor(Math.random() * len)); } 测试环境为: 1.电脑:iMac(10.13.6): 2.处理器:4.2 GHz Intel Core i7: 3.浏览器:Chrome(89.0.4389.82) 1. for 循环 for

JavaScript之事件循环案例讲解

js中的事件循环 因为JavaScript是单线程的,同一事件只能执行一种方法,所以会将程序中的方法加入到执行栈中按照后进先出的顺序依次执行,当遇见异步任务时不会被阻塞,而是将任务放入事件队列中,继续执行执行栈中的同步代码,等当前执行栈中的所有任务都执行完毕则查找事件队列中的任务,并把任务的回调函数放入执行栈中,执行其中的同步代码,如此反复形成的循环被称为事件循环. node.js node.js特点 事件驱动 从上向下执行代码,当遇到需要回调的地方就加入到事件队列中,主线程运行完就去执行事件队

JavaScript中三种for循环语句的使用总结(for、for...in、for...of)

前言 每个接触JS的开发人员都不可避免的与for循环打交道,毕竟这是遍历必不可少的工具之一.JavaScript 中的 for 循环语句相信大家都已经快用厌了,现在有好多文章都在讲怎么减少代码中的 for 循环语句,但是,你又不得不承认它们真的很有用.今天,我来总结一下前端 JavaScript 中三种 for 循环语句. for 这大概是应用最广的循环语句了吧,简单实用,且大多数时候性能还是在线的,唯一的缺点大概就是太普通,没有特色,导致很多人现在不愿用它. const array = [4,

JavaScript循环遍历的24个方法,你都知道吗

目录 前言 一.数组遍历方法 1. forEach() 2. map() 3. for of 4. filter() 5. some().every() 6. reduce().reduceRight() 7. find().findIndex() 8. keys().values().entries() 二.对象遍历方法 1. for in 2. Object.keys().Object.values().Object.entries() 3. Object.getOwnPropertyNam

JavaScript循环遍历你会用哪些之小结篇

总结JavaScript中的循环遍历 定义一个数组和对象 const arr = ['a', 'b', 'c', 'd', 'e', 'f']; const obj = { a: 1, b: 2, c: 3, d: 4 } for() 经常用来遍历数组元素 遍历值为数组元素索引 for (let i = 0; len = arr.length, i < len; i++) { console.log(i); // 0 1 2 3 4 5 console.log(arr[i]); // a b c

JS循环遍历JSON数据的方法

JSON数据如:{"options":"[{/"text/":/"王家湾/",/"value/":/"9/"},{/"text/":/"李家湾/",/"valu e/":/"10/"},{/"text/":/"邵家湾/",/"value/":/"13

JavaScript 中的12种循环遍历方法【总结】

1.for 循环 let arr = [1,2,3]; for (let i=0; i<arr.length; i++){ console.log(i,arr[i]) } // 0 1 // 1 2 // 2 3 for 循环是 Js 中最常用的一个循环工具,经常用于数组的循环遍历. 2.for in 循环 let obj = {name:'zhou',age:'**'} for(let i in obj){ console.log(i,obj[i]) } // name zhou // age

JavaScript中的数组遍历forEach()与map()方法以及兼容写法介绍

•原理: •高级浏览器支持forEach方法 语法:forEach和map都支持2个参数:一个是回调函数(item,index,list)和上下文: •forEach:用来遍历数组中的每一项:这个方法执行是没有返回值的,对原来数组也没有影响: •数组中有几项,那么传递进去的匿名回调函数就需要执行几次: •每一次执行匿名函数的时候,还给其传递了三个参数值:数组中的当前项item,当前项的索引index,原始数组input: •理论上这个方法是没有返回值的,仅仅是遍历数组中的每一项,不对原来数组进行

Javascript数组循环遍历之forEach详解

1.js 数组循环遍历. 数组循环变量,最先想到的就是 for(var i=0;i<count;i++)这样的方式了. 除此之外,也可以使用较简便的forEach 方式 2.forEach函数. Firefox 和Chrome 的Array 类型都有forEach的函数.使用如下: <!--Add by oscar999--> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> &l

javascript先序遍历DOM树的方法

DOM树由文档中的所有节点(元素节点.文本节点.注释节点等)所构成的一个树结构,DOM树的解析和构建是浏览器要实现的关键功能.既然DOM树是一个树结构,那么我们就可以使用遍历树结构的相关方法来对DOM树进行遍历,同时DOM2中的"Traversal"模块又提供了两种新的类型,从而可以很方便地实现DOM树的先序遍历. 注:本文中的5种方法都是对DOM的先序遍历方法(深度优先遍历),并且只关注Element类型. 1. 使用DOM1中的基础接口,递归遍历DOM树 DOM1中为基础类型Nod

Javascript循环删除数组中元素的几种方法示例

本文主要跟大家分享了关于Javascript循环删除数组中元素的几种方法,分享出来供大家参考学习,下面来看看详细的介绍: 发现问题 大家在码代码的过程中,经常会遇到在循环中移除指定元素的需求.按照常规的思路,直接一个for循环,然后在循环里面来个if判断,在判断中删除掉指定元素即可.但是实际情况往往不会像预想的那样顺利运行. 下面以一段Javascript代码为例演示这一过程. (function () { var arr = [1,2,2,3,4,5]; var len = arr.lengt

js 实现获取name 相同的页面元素并循环遍历的方法

实例如下: <input type="hidden" name="blues" value="蓝色浏阳河之最"> <input type="hidden" name="blues" value="蓝色浏阳河之亲"> <input type="hidden" name="blues" value="蓝色浏阳河之

JavaScript实现二叉树定义、遍历及查找的方法详解

本文实例讲述了JavaScript实现二叉树定义.遍历及查找的方法.分享给大家供大家参考,具体如下: 二叉树(binary tree) 在写这篇文章之前说一下数据结构和算法这个系列,这个系列包含了很多东西,比如啥子排序,线性表,广义表,树,图这些大家都是知道的,但是这些东西我们学了之后工作中能用到的又有多少呢,据我所知绝大部分公司,一线码农,屌丝,程序猿是用不到这些东西,既然这样为啥子我还要强调这个系列呢,本人觉得算法和数据结构是程序的基本功,前提想脱离一线码农,普通程序猿行列,说得通俗一点就是

layuiAdmin循环遍历展示商品图片列表的方法

主页面内容 <div class="layui-fluid layadmin-cmdlist-fluid"> <script id="demo2" type="text/html"> <div class="layui-col-md2 layui-col-sm4"> <div class="cmdlist-container"> <a lay-href=