29人参与 • 2025-02-14 • Javascript
最简单的一种,也是使用频率最高的一种,虽然性能不弱,但仍有优化空间
const arr = [11, 22, 33, 44, 55, 66, 77, 88]; for (let i = 0; i < arr.length; i++) { console.log(arr[i]); }
打印结果:
const arr = [11, 22, 33, 44, 55, 66, 77, 88]; let len = arr.length for (let i = 0; i < len; i++) { console.log(arr[i]); }
简要说明:使用临时变量,将长度缓存起来,避免重复计算数组长度,当数组较大时优化效果才会比较明显 缺点:不能在for循环中操作list的大小,比如除去或新加一个元素。 这种方法基本上是所有循环遍历方法中性能最高的一种
1.)foreach() 遍历普通数组
const arr = [11, 22, 33, 44, 55, 66, 77, 88]; arr.foreach(item => { //foreach循环 console.log(item); });
打印结果:
2.)foreach() 遍历对象类型数组
const arrobj = [ { id: 1, name: "张三", value: 10 }, { id: 2, name: "李四", value: 20 }, { id: 3, name: "王五", value: 30 } ]; arrobj.foreach(item => { console.log(item.id + "-------" + item.name); item.value *= 10 }); console.log(arrobj)
打印结果:
简要说明: 数组自带的foreach循环,使用频率较高,实际上性能比普通for循环弱。原因如下:
一般情况下,普通的 for 循环确实比 foreach 循环有更好的性能,这是因为 foreach 本质上是一个函数调用的过程,而函数调用会带来额外的开销。 具体来说,foreach 循环在每次迭代时都需要执行一次回调函数,并且要对回调函数的执行上下文进行绑定,这样就需要创建和销毁大量的函数堆栈,导致额外的系统开销。而普通的 for 循环则不需要执行函数调用操作,在每次迭代中直接访问元素,极大地提高了代码的执行速度。
使用 foreach 时需要注意几个点:
1)其实对于 foreach 方法,它本身是无法通过 break 或者 return 来中途停止循环的。foreach 方法会遍历数组的每个元素,并对每个元素执行提供的回调函数。无论回调函数中使用了 return 还是 break,都无法停止或跳出整个循环。 中断方法:
使用
try/catch
监视代码块,在需要中断的地方抛出异常。官方推荐方法(替换方法):用
every
和some
代替 foreach 函数。every
再碰到return false
时候,终止循环;some
在碰到return true
时候,终止循环。
- foreach() 方法不会改变原数组。它只是对数组中的每个元素执行提供的函数,而不会对数组本身进行修改或返回一个新的数组。
- 如果在 foreach() 中对数组中的对象进行修改(比如改变对象的属性),那么这些对象的内容会被改变,因为对象是引用类型。
3)foreach 中使用 await 异步代码会导致 foreach 并不能保证按顺序执行。可以改成使用for...of,因为for...of使用迭代器去遍历,会按照迭代器对象定义的顺序,从前往后依次遍历。
针对第二点我们看下面的代码示例:
const arr = [1, 2, 3]; arr.foreach(num => { console.log(num * 2); // 只是打印结果,不改变原数组 }); console.log(arr); // 输出: [1, 2, 3] // 对于对象的情况 const objarr = [{ value: 1 }, { value: 2 }]; objarr.foreach(item => { item.value *= 2; // 修改了对象的属性 }); console.log(objarr); // 输出: [{ value: 2 }, { value: 4 }]
针对第三点我们看下面的代码示例:
async function test() { let arr = [4, 2, 1] arr.foreach(async item => { const res = await handle(item) console.log(res) }) console.log('结束') } function handle(x) { return new promise((resolve, reject) => { settimeout(() => { resolve(x) }, 1000 * x) }) } test()
我们期望的结果是:
4
2
1
结束
但实际上会输出:
结束
1
2
4
具体原因
因为 foreach 底层实现是拿过来直接执行了,这就导致它无法保证异步任务的执行顺序。比如后面的任务用时短,那么就又可能抢在前面的任务之前执行。
解决方案 其实也很简单, 我们利用for...of
就能轻松解决。
async function test() { let arr = [4, 2, 1] for(const item of arr) { const res = await handle(item) console.log(res) } console.log('结束') }
1. map即是 “映射”的意思 ,原数组被“映射”成对应新数组 **2. map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
map() 不会改变原始数组。
map() 不会对空数组进行检测。** 5. map支持return
const arr = [11, 22, 33, 44, 55, 66, 77, 88]; var newarr = arr.map((value, index) => { console.log(value + "----" + index); return value * 10; }); console.log(newarr);
打印结果:
简要说明: 这种方式也是用的比较广泛的,虽然用起来比较优雅,但实际效率还比不上foreach
foreach()和map()区别:
两者都是用来遍历数组的。
返回值:
foreach() 方法没有返回值(或者说返回 undefined),它只是对数组的每个元素执行指定的回调函数。
map() 方法返回一个新的数组,该数组包含对原数组每个元素执行回调函数后的结果。
原数组的改变:
foreach() 方法不会改变原数组。它只是对数组中的每个元素执行提供的函数,而不是对数组本身进行修改或返回一个新数组。但是,如果在foreach() 中对数组中的对象进行修改(比如改变对象的属性),那么这些对象的内容会被改变,因为对象是引用类型。
map() 方法不会改变原数组,而是返回一个新的数组,该数组由原数组经过回调函数操作后的结果组成。
支持链式调用: foreach不支持链式调用,而map支持链式调用,可以继续对返回的新数组进行操作。
const array3 = [1, 2, 3, 4, 5]; const doubledsum = array3 .map((element) => element * 2) .reduce((accumulator, currentvalue) => accumulator + currentvalue, 0); console.log(doubledsum); // 输出: 30
filter用于对数组进行过滤。 filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。 filter() 不会对空数组进行检测;不会改变原始数组
array.filter(function(currentvalue,index,arr), thisvalue)
let arr = [56, 15, 48, 3, 7]; let newarr = arr.filter(function (value, index, array) { return value % 2 === 0; }); console.log(newarr) // [56, 48]
作为es6新增的循环方法,个人觉得相当好用,而且方便。这个方法避开了for-in循环的所有缺陷。而且,它可以正确响应break、continue和return语句。
//循环数组 let arr = ['123','qwewq','sfds']; for(let item of arr){ console.log(item); //item指的的就是数组每一项的值。不是索引。 } //输出 //'123' //'qwewq' //'sfds'
for-of循环支持数组、字符串、set、map 等。但是for of也有一个致命伤,就像例子看到的,没有索引。对,这是优点也是缺点。遍历数组对象,直接就是item.属性(或者item[属性]),而不用像for循环那样arr[index].属性(arrindex)。但是你有的时候真的就得用到index。不好意思,只能把数组转成map()。但我觉得真的需要用到index,还是换成foreach吧。
简要说明: 这种方式是es6里面用到的,性能要好于forin,但仍然比不上普通for循环
for in循环是用来遍历对象的。要知道javascript对象的所有属性都是字符串,不过属性对应的值可以是任意数据类型。(注意:遍历时不仅能读取对象自身上面的成员属性,也能遍历出对象的原型属性)
let obj = {a:1, b:2, c:3}; for (let prop in obj) { //prop指对象的属性名 console.log(prop, obj[prop]); } // 输出: // a,1 // b,2 // c,3
for in同样可以用来循环数组,但是不推荐这么做。由于array也是对象,而它的每个元素的索引被视为对象的属性,因此,for in循环可以直接循环出array的索引,但得到的是string而不是number,所以一旦你想用这个index去进行计算,就会出错。而且因为会遍历原型属性,所以可能得出的结果不会是你想要的(具体细节不多说,需要了解的自己查询,反正很多坑)。虽然可以用hasownproperty()方法避免这个缺陷,但是何必呢,循环方法那么多,换一个就是了。
for (var index in myarray) { // 不推荐这样 console.log(myarray[index]); }
为什么用for ... in?
简要说明: 这个循环很多人爱用,但实际上,经分析测试,在众多的循环遍历方式中 它的效率是最低的
关于for ...of 和 for ...in 区别
for of 和 for in 是两种不同的循环语句,用于遍历可迭代对象
和枚举对象的属性
,它们的区别如下:
1)遍历的对象类型不同
for of
用于遍历可迭代对象,如数组、字符串、set、map等;不会遍历原型链。for in
主要遍历对象,不适用遍历数组;会遍历对象的整个原型链,性能差一些。2)遍历获取的内容不同
for of
遍历获取的是对象的键值
。for in
遍历获取的是对象的键名
(属性名)。3)遍历顺序不同
for of
按照迭代器对象定义的顺序,从前往后依次遍历。for in
遍历对象属性名时,顺序不确定,可能是随机的。(这也是不推荐用在数组上的原因之一)4)可以使用的对象类型不同
for of
适用于可迭代对象,如数组、字符串、set、map等;for in
适用于所有对象,包括普通对象、数组、字符串等。注意:普通对象用 for of
遍历会报错。如果是类数组对象的话可以用array.from() 转成数组再遍历。
let forobject = array.from({ 0: 'one', 1: 'two', 2: 'three', length: 3 }) for (let item of forobject) { console.log(item, 'item') }
- 遍历数组,找到第一个符合条件的项,并返回该项;不会继续遍历数组;否则返回undefined
- 不会改变数组
[1,4,-5,10].find((n) => n < 0 ) //-5
上面代码找出数组中第一个小于0的成员
[1,5,10,15].find(function(value,index,arr){ return value > 9 }) //10
上面代码中,find
方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组。
- 遍历数组找到第一个符合条件的项,并返回该项的索引值;不会继续遍历数组;否则返回-1。
- 不会改变数组
[1,5,10,15].findindex(function(value,index,arr){ return value > 9 }) //2
findindex()
当中的回调函数也是接收三个参数,与find() 相同。
1)如果有一个元素满足条件,则表达式返回true,剩余的元素不会再执行检测。 2)如果没有满足条件的元素,则返回false。 3)返回值是布尔值
注意:
1) some() 不会对空数组进行检测。 2) some() 不会改变原始数组。
var ages = [3, 18, 17, 16] var checkoutval = function checkout (age) { console.log(age >= 18) // false true 有一个满足条件的会停止检测剩余的元素 return age >= 18 } console.log(ages.some(checkoutval)) // true
let somearr = [2,3,4]; let someresult = somearr.some((item, index)=>{ return item > 3 }); console.log(someresult); // 结果为: true
1)如果数组中有一个元素不满足,则整个表达式返回false;且剩余的元素不会再进行检测 2)如果所有元素都满足条件,则返回true。 3)返回值是布尔值
注意:
1) every() 不会对空数组进行检测。 2) every() 不会改变原始数组。
var ages = [3, 18, 17, 16] const fn = (currentvalue) => currentvalue < 40 console.log(ages.every(fn)) // true 值全都符合函数条件
let everyarr = [2,3,4]; let everyresult = everyarr.every((item, index)=>{ return item > 0 }); console.log(everyresult); // 结果为: true
array.some() 和array.every() 的区别???
reduce() 方法接受一个回调函数
和一个可选的初始值
作为参数,对数组中的每个元素依次调用回调函数,并将上一次调用的结果传递给下一次调用,最终返回一个累积的结果。
array.reduce(callback, initialvalue)
使用案例:
// reducer let reducearr = [0,1,2,3,4] let reduceresult = reducearr.reduce((a, b)=>{ return a + b; }); console.log(reduceresult); // 结果: 10
上述列举了几种方式都有一一做过对比分析,基本上可以得出的结论是: 普通for循环才是最优雅的,优化后的for循环最快
注意:
数组方法无法中途停止循环,所以都不可以使用break和continue; for循环之类的不可以return,但是能正常使用break和continue;
以上就是js中循环遍历数组的几种常用方式总结的详细内容,更多关于js循环遍历数组的资料请关注代码网其它相关文章!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论