JS中循環(huán)遍歷數(shù)組的幾種常用方式總結(jié)
第一種:for循環(huán),也是最常見的
最簡單的一種,也是使用頻率最高的一種,雖然性能不弱,但仍有優(yōu)化空間
const arr = [11, 22, 33, 44, 55, 66, 77, 88]; for (let i = 0; i < arr.length; i++) { console.log(arr[i]); }
打印結(jié)果:
第二種:優(yōu)化版for循環(huán)
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]); }
簡要說明:使用臨時(shí)變量,將長度緩存起來,避免重復(fù)計(jì)算數(shù)組長度,當(dāng)數(shù)組較大時(shí)優(yōu)化效果才會(huì)比較明顯 缺點(diǎn):不能在for循環(huán)中操作list的大小,比如除去或新加一個(gè)元素。 這種方法基本上是所有循環(huán)遍歷方法中性能最高的一種
第三種:forEach()
1.)forEach() 遍歷普通數(shù)組
const arr = [11, 22, 33, 44, 55, 66, 77, 88]; arr.forEach(item => { //forEach循環(huán) console.log(item); });
打印結(jié)果:
2.)forEach() 遍歷對(duì)象類型數(shù)組
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)
打印結(jié)果:
簡要說明: 數(shù)組自帶的foreach循環(huán),使用頻率較高,實(shí)際上性能比普通for循環(huán)弱。原因如下:
一般情況下,普通的 for 循環(huán)確實(shí)比 forEach 循環(huán)有更好的性能,這是因?yàn)?forEach 本質(zhì)上是一個(gè)函數(shù)調(diào)用的過程,而函數(shù)調(diào)用會(huì)帶來額外的開銷。 具體來說,forEach 循環(huán)在每次迭代時(shí)都需要執(zhí)行一次回調(diào)函數(shù),并且要對(duì)回調(diào)函數(shù)的執(zhí)行上下文進(jìn)行綁定,這樣就需要?jiǎng)?chuàng)建和銷毀大量的函數(shù)堆棧,導(dǎo)致額外的系統(tǒng)開銷。而普通的 for 循環(huán)則不需要執(zhí)行函數(shù)調(diào)用操作,在每次迭代中直接訪問元素,極大地提高了代碼的執(zhí)行速度。
使用 forEach 時(shí)需要注意幾個(gè)點(diǎn):
1)其實(shí)對(duì)于 forEach 方法,它本身是無法通過 break 或者 return 來中途停止循環(huán)的。forEach 方法會(huì)遍歷數(shù)組的每個(gè)元素,并對(duì)每個(gè)元素執(zhí)行提供的回調(diào)函數(shù)。無論回調(diào)函數(shù)中使用了 return 還是 break,都無法停止或跳出整個(gè)循環(huán)。 中斷方法:
使用
try/catch
監(jiān)視代碼塊,在需要中斷的地方拋出異常。官方推薦方法(替換方法):用
every
和some
代替 forEach 函數(shù)。every
再碰到return false
時(shí)候,終止循環(huán);some
在碰到return true
時(shí)候,終止循環(huán)。
- forEach() 方法不會(huì)改變原數(shù)組。它只是對(duì)數(shù)組中的每個(gè)元素執(zhí)行提供的函數(shù),而不會(huì)對(duì)數(shù)組本身進(jìn)行修改或返回一個(gè)新的數(shù)組。
- 如果在 forEach() 中對(duì)數(shù)組中的對(duì)象進(jìn)行修改(比如改變對(duì)象的屬性),那么這些對(duì)象的內(nèi)容會(huì)被改變,因?yàn)閷?duì)象是引用類型。
3)forEach 中使用 await 異步代碼會(huì)導(dǎo)致 forEach 并不能保證按順序執(zhí)行??梢愿某墒褂胒or...of,因?yàn)閒or...of使用迭代器去遍歷,會(huì)按照迭代器對(duì)象定義的順序,從前往后依次遍歷。
針對(duì)第二點(diǎn)我們看下面的代碼示例:
const arr = [1, 2, 3]; arr.forEach(num => { console.log(num * 2); // 只是打印結(jié)果,不改變原數(shù)組 }); console.log(arr); // 輸出: [1, 2, 3] // 對(duì)于對(duì)象的情況 const objArr = [{ value: 1 }, { value: 2 }]; objArr.forEach(item => { item.value *= 2; // 修改了對(duì)象的屬性 }); console.log(objArr); // 輸出: [{ value: 2 }, { value: 4 }]
針對(duì)第三點(diǎn)我們看下面的代碼示例:
async function test() { let arr = [4, 2, 1] arr.forEach(async item => { const res = await handle(item) console.log(res) }) console.log('結(jié)束') } function handle(x) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(x) }, 1000 * x) }) } test()
我們期望的結(jié)果是:
4
2
1
結(jié)束
但實(shí)際上會(huì)輸出:
結(jié)束
1
2
4
具體原因
因?yàn)?forEach 底層實(shí)現(xiàn)是拿過來直接執(zhí)行了,這就導(dǎo)致它無法保證異步任務(wù)的執(zhí)行順序。比如后面的任務(wù)用時(shí)短,那么就又可能搶在前面的任務(wù)之前執(zhí)行。
解決方案 其實(shí)也很簡單, 我們利用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('結(jié)束') }
第四種:map()
定義和用法
1. map即是 “映射”的意思 ,原數(shù)組被“映射”成對(duì)應(yīng)新數(shù)組 **2. map() 方法返回一個(gè)新數(shù)組,數(shù)組中的元素為原始數(shù)組元素調(diào)用函數(shù)處理后的值。
map() 不會(huì)改變原始數(shù)組。
map() 不會(huì)對(duì)空數(shù)組進(jìn)行檢測。** 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);
打印結(jié)果:
簡要說明: 這種方式也是用的比較廣泛的,雖然用起來比較優(yōu)雅,但實(shí)際效率還比不上foreach
forEach()和map()區(qū)別:
兩者都是用來遍歷數(shù)組的。
返回值:
forEach() 方法沒有返回值(或者說返回 undefined),它只是對(duì)數(shù)組的每個(gè)元素執(zhí)行指定的回調(diào)函數(shù)。
map() 方法返回一個(gè)新的數(shù)組,該數(shù)組包含對(duì)原數(shù)組每個(gè)元素執(zhí)行回調(diào)函數(shù)后的結(jié)果。
原數(shù)組的改變:
forEach() 方法不會(huì)改變原數(shù)組。它只是對(duì)數(shù)組中的每個(gè)元素執(zhí)行提供的函數(shù),而不是對(duì)數(shù)組本身進(jìn)行修改或返回一個(gè)新數(shù)組。但是,如果在forEach() 中對(duì)數(shù)組中的對(duì)象進(jìn)行修改(比如改變對(duì)象的屬性),那么這些對(duì)象的內(nèi)容會(huì)被改變,因?yàn)閷?duì)象是引用類型。
map() 方法不會(huì)改變原數(shù)組,而是返回一個(gè)新的數(shù)組,該數(shù)組由原數(shù)組經(jīng)過回調(diào)函數(shù)操作后的結(jié)果組成。
支持鏈?zhǔn)秸{(diào)用: foreach不支持鏈?zhǔn)秸{(diào)用,而map支持鏈?zhǔn)秸{(diào)用,可以繼續(xù)對(duì)返回的新數(shù)組進(jìn)行操作。
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用于對(duì)數(shù)組進(jìn)行過濾。 filter() 方法創(chuàng)建一個(gè)新的數(shù)組,新數(shù)組中的元素是通過檢查指定數(shù)組中符合條件的所有元素。 filter() 不會(huì)對(duì)空數(shù)組進(jìn)行檢測;不會(huì)改變原始數(shù)組
語法
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]
第六種:for....of 方法
作為ES6新增的循環(huán)方法,個(gè)人覺得相當(dāng)好用,而且方便。這個(gè)方法避開了for-in循環(huán)的所有缺陷。而且,它可以正確響應(yīng)break、continue和return語句。
//循環(huán)數(shù)組 let arr = ['123','qwewq','sfds']; for(let item of arr){ console.log(item); //item指的的就是數(shù)組每一項(xiàng)的值。不是索引。 } //輸出 //'123' //'qwewq' //'sfds'
for-of循環(huán)支持?jǐn)?shù)組、字符串、Set、Map 等。但是for of也有一個(gè)致命傷,就像例子看到的,沒有索引。對(duì),這是優(yōu)點(diǎn)也是缺點(diǎn)。遍歷數(shù)組對(duì)象,直接就是item.屬性(或者item[屬性]),而不用像for循環(huán)那樣arr[index].屬性(arrindex)。但是你有的時(shí)候真的就得用到index。不好意思,只能把數(shù)組轉(zhuǎn)成Map()。但我覺得真的需要用到index,還是換成forEach吧。
簡要說明: 這種方式是es6里面用到的,性能要好于forin,但仍然比不上普通for循環(huán)
第七種:for....in 方法
for in循環(huán)是用來遍歷對(duì)象的。要知道JavaScript對(duì)象的所有屬性都是字符串,不過屬性對(duì)應(yīng)的值可以是任意數(shù)據(jù)類型。(注意:遍歷時(shí)不僅能讀取對(duì)象自身上面的成員屬性,也能遍歷出對(duì)象的原型屬性)
語法
let obj = {a:1, b:2, c:3}; for (let prop in obj) { //prop指對(duì)象的屬性名 console.log(prop, obj[prop]); } // 輸出: // a,1 // b,2 // c,3
for in同樣可以用來循環(huán)數(shù)組,但是不推薦這么做。由于Array也是對(duì)象,而它的每個(gè)元素的索引被視為對(duì)象的屬性,因此,for in循環(huán)可以直接循環(huán)出Array的索引,但得到的是String而不是Number,所以一旦你想用這個(gè)index去進(jìn)行計(jì)算,就會(huì)出錯(cuò)。而且因?yàn)闀?huì)遍歷原型屬性,所以可能得出的結(jié)果不會(huì)是你想要的(具體細(xì)節(jié)不多說,需要了解的自己查詢,反正很多坑)。雖然可以用hasOwnProperty()方法避免這個(gè)缺陷,但是何必呢,循環(huán)方法那么多,換一個(gè)就是了。
for (var index in myArray) { // 不推薦這樣 console.log(myArray[index]); }
為什么用for ... in?
簡要說明: 這個(gè)循環(huán)很多人愛用,但實(shí)際上,經(jīng)分析測試,在眾多的循環(huán)遍歷方式中 它的效率是最低的
關(guān)于for ...of 和 for ...in 區(qū)別
for of 和 for in 是兩種不同的循環(huán)語句,用于遍歷可迭代對(duì)象
和枚舉對(duì)象的屬性
,它們的區(qū)別如下:
1)遍歷的對(duì)象類型不同
for of
用于遍歷可迭代對(duì)象,如數(shù)組、字符串、Set、Map等;不會(huì)遍歷原型鏈。for in
主要遍歷對(duì)象,不適用遍歷數(shù)組;會(huì)遍歷對(duì)象的整個(gè)原型鏈,性能差一些。
2)遍歷獲取的內(nèi)容不同
for of
遍歷獲取的是對(duì)象的鍵值
。for in
遍歷獲取的是對(duì)象的鍵名
(屬性名)。
3)遍歷順序不同
for of
按照迭代器對(duì)象定義的順序,從前往后依次遍歷。for in
遍歷對(duì)象屬性名時(shí),順序不確定,可能是隨機(jī)的。(這也是不推薦用在數(shù)組上的原因之一)
4)可以使用的對(duì)象類型不同
for of
適用于可迭代對(duì)象,如數(shù)組、字符串、Set、Map等;for in
適用于所有對(duì)象,包括普通對(duì)象、數(shù)組、字符串等。
注意:普通對(duì)象用 for of
遍歷會(huì)報(bào)錯(cuò)。如果是類數(shù)組對(duì)象的話可以用Array.from() 轉(zhuǎn)成數(shù)組再遍歷。
let forObject = Array.from({ 0: 'one', 1: 'two', 2: 'three', length: 3 }) for (let item of forObject) { console.log(item, 'item') }
第八種:find方法
- 遍歷數(shù)組,找到第一個(gè)符合條件的項(xiàng),并返回該項(xiàng);不會(huì)繼續(xù)遍歷數(shù)組;否則返回undefined
- 不會(huì)改變數(shù)組
[1,4,-5,10].find((n) => n < 0 ) //-5
上面代碼找出數(shù)組中第一個(gè)小于0的成員
[1,5,10,15].find(function(value,index,arr){ return value > 9 }) //10
上面代碼中,find
方法的回調(diào)函數(shù)可以接受三個(gè)參數(shù),依次為當(dāng)前的值、當(dāng)前的位置和原數(shù)組。
第九種:findIndex方法
- 遍歷數(shù)組找到第一個(gè)符合條件的項(xiàng),并返回該項(xiàng)的索引值;不會(huì)繼續(xù)遍歷數(shù)組;否則返回-1。
- 不會(huì)改變數(shù)組
[1,5,10,15].findIndex(function(value,index,arr){ return value > 9 }) //2
findIndex()
當(dāng)中的回調(diào)函數(shù)也是接收三個(gè)參數(shù),與find() 相同。
第十種:Array.some() 方法
1)如果有一個(gè)元素滿足條件,則表達(dá)式返回true,剩余的元素不會(huì)再執(zhí)行檢測。 2)如果沒有滿足條件的元素,則返回false。 3)返回值是布爾值
注意:
1) some() 不會(huì)對(duì)空數(shù)組進(jìn)行檢測。 2) some() 不會(huì)改變原始數(shù)組。
var ages = [3, 18, 17, 16] var checkoutVal = function checkout (age) { console.log(age >= 18) // false true 有一個(gè)滿足條件的會(huì)停止檢測剩余的元素 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); // 結(jié)果為: true
第十一種:Array.every() 方法 (所有的,每一個(gè))
1)如果數(shù)組中有一個(gè)元素不滿足,則整個(gè)表達(dá)式返回false;且剩余的元素不會(huì)再進(jìn)行檢測 2)如果所有元素都滿足條件,則返回true。 3)返回值是布爾值
注意:
1) every() 不會(huì)對(duì)空數(shù)組進(jìn)行檢測。 2) every() 不會(huì)改變原始數(shù)組。
var ages = [3, 18, 17, 16] const fn = (currentValue) => currentValue < 40 console.log(ages.every(fn)) // true 值全都符合函數(shù)條件
let everyArr = [2,3,4]; let everyResult = everyArr.every((item, index)=>{ return item > 0 }); console.log(everyResult); // 結(jié)果為: true
Array.some() 和Array.every() 的區(qū)別???
第十二種:reduce() 方法
reduce() 方法接受一個(gè)回調(diào)函數(shù)
和一個(gè)可選的初始值
作為參數(shù),對(duì)數(shù)組中的每個(gè)元素依次調(diào)用回調(diào)函數(shù),并將上一次調(diào)用的結(jié)果傳遞給下一次調(diào)用,最終返回一個(gè)累積的結(jié)果。
array.reduce(callback, initialValue)
- 其中,callback 是一個(gè)函數(shù),它可以接受四個(gè)參數(shù):accumulator(累加器)、currentValue(當(dāng)前值)、currentIndex(當(dāng)前索引)和 array(當(dāng)前數(shù)組)。 initialValue 是可選的初始值,
- 如果提供了初始值,則作為第一次調(diào)用回調(diào)函數(shù)時(shí)的 accumulator 值;
- 如果沒有提供初始值,則使用數(shù)組的第一個(gè)元素作為初始值,并從第二個(gè)元素開始調(diào)用回調(diào)函數(shù)。
使用案例:
// reducer let reduceArr = [0,1,2,3,4] let reduceResult = reduceArr.reduce((a, b)=>{ return a + b; }); console.log(reduceResult); // 結(jié)果: 10
上述列舉了幾種方式都有一一做過對(duì)比分析,基本上可以得出的結(jié)論是: 普通for循環(huán)才是最優(yōu)雅的,優(yōu)化后的for循環(huán)最快
注意:
數(shù)組方法無法中途停止循環(huán),所以都不可以使用break和continue; for循環(huán)之類的不可以return,但是能正常使用break和continue;
以上就是JS中循環(huán)遍歷數(shù)組的幾種常用方式總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于JS循環(huán)遍歷數(shù)組的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于JS通過google翻譯插件實(shí)現(xiàn)多語言版本
這篇文章主要介紹了JS通過google翻譯插件實(shí)現(xiàn)多語言版本,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06js模仿windows桌面圖標(biāo)排列算法具體實(shí)現(xiàn)(附圖)
需要引入Jquery,如果需要全部功能,請引入jquery-ui和jquery-ui.css,具體實(shí)現(xiàn)步驟如下,感興趣的朋友可以參考下哈2013-06-06clipboard.js在移動(dòng)端復(fù)制失敗的解決方法
最近在使用clipboard.js碰到的一個(gè)小問題,通過查找相關(guān)資料解決了,所以下面這篇文章主要給大家介紹了關(guān)于clipboard.js在移動(dòng)端復(fù)制失敗的解決方法,需要的朋友可以參考借鑒,下面來一起學(xué)習(xí)學(xué)習(xí)吧2018-06-06使用js檢測瀏覽器是否支持html5中的video標(biāo)簽的方法
這篇文章主要介紹了使用js檢測瀏覽器是否支持html5中的video標(biāo)簽的方法,需要的朋友可以參考下2014-03-03精通Javascript系列之?dāng)?shù)據(jù)類型 字符串
下面先講一下字符串String字符串由零個(gè)或者多個(gè)字符構(gòu)成。字符可以包括字母、數(shù)字、標(biāo)點(diǎn)符號(hào)和空格。2011-06-06JavaScript執(zhí)行環(huán)境及作用域鏈實(shí)例分析
這篇文章主要介紹了JavaScript執(zhí)行環(huán)境及作用域鏈,結(jié)合實(shí)例形式分析了JavaScript執(zhí)行環(huán)境及作用域鏈的相關(guān)概念、功能與使用技巧,需要的朋友可以參考下2018-08-08