JS中數(shù)組常用的循環(huán)遍歷你會(huì)幾種
前言
數(shù)組和對(duì)象作為一個(gè)最基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),在各種編程語言中都充當(dāng)著至關(guān)重要的角色,你很難想象沒有數(shù)組和對(duì)象的編程語言會(huì)是什么模樣,特別是 JS ,弱類型語言,非常靈活。本文帶你了解常用數(shù)組遍歷、對(duì)象遍歷的使用對(duì)比以及注意事項(xiàng)。
數(shù)組遍歷
隨著 JS 的不斷發(fā)展,截至 ES7 規(guī)范已經(jīng)有十多種遍歷方法。下面按照功能類似的方法為一組,來介紹數(shù)組的常用遍歷方法。
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 });
小結(jié)
- 三者都是基本的由左到右遍歷數(shù)組。
- forEach 無法跳出循環(huán),for 和 for ..of 可以使用 break 或者 continue 跳過或中斷。
- for ...of 直接訪問的是實(shí)際元素,for 遍歷數(shù)組索引,forEach 回調(diào)函數(shù)參數(shù)更豐富,元素、索引、原數(shù)組都可以獲取。
- for ...of 與 for 如果數(shù)組中存在空元素,同樣會(huì)執(zhí)行。
some、every
const list = [ { name: '頭部導(dǎo)航', 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
小結(jié)
- 二者都是用來做數(shù)組條件判斷的,都是返回一個(gè)布爾值。
- 二者都可以被中斷。
- some 若某一元素滿足條件,返回 true,循環(huán)中斷。所有元素不滿足條件,返回 false。
- every 與 some 相反,若有一元素不滿足條件,返回 false,循環(huán)中斷。所有元素滿足條件,返回 true。
filter、map
const list = [ { name: '頭部導(dǎo)航', 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: '頭部導(dǎo)航', 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: '頭部導(dǎo)航', type: 'nav', id: 1 }, // empty, // { name: '輪播', type: 'content', id: 2 }, // { name: '頁腳', type: 'nav', id: 3 }, // ]
小結(jié)
- 二者都是生成一個(gè)新數(shù)組,都不會(huì)改變原數(shù)組(不包括遍歷對(duì)象數(shù)組時(shí),在回調(diào)函數(shù)中操作元素對(duì)象)。
- 二者都會(huì)跳過空元素。有興趣的同學(xué)可以自己打印一下。
- map 會(huì)將回調(diào)函數(shù)的返回值組成一個(gè)新數(shù)組,數(shù)組長度與原數(shù)組一致。
- filter 會(huì)將符合回調(diào)函數(shù)條件的元素組成一個(gè)新數(shù)組。
- map 生成的新數(shù)組元素是可自定義。
- filter 生成的新數(shù)組元素不可自定義,與對(duì)應(yīng)原數(shù)組元素一致。
find、findIndex
const list = [ { name: '頭部導(dǎo)航', id: 1 }, { name: '輪播', id: 2 }, { name: '頁腳', id: 3 }, ]; const result = list.find((item) => item.id === 3); // result: { name: '頁腳', id: 3 } result.name = '底部導(dǎo)航'; // list: [ // { name: '頭部導(dǎo)航', id: 1 }, // { name: '輪播', id: 2 }, // { name: '底部導(dǎo)航', id: 3 }, // ] const index = list.findIndex((item) => item.id === 3); // index: 2 list[index].name // '底部導(dǎo)航';
小結(jié)
- 二者都是用來查找數(shù)組元素。
- find 方法返回?cái)?shù)組中滿足 callback 函數(shù)的第一個(gè)元素的值。如果不存在返回 undefined。
- findIndex 它返回?cái)?shù)組中找到的元素的索引,而不是其值,如果不存在返回 -1。
reduce、reduceRight
reduce 方法接收兩個(gè)參數(shù),第一個(gè)參數(shù)是回調(diào)函數(shù)(callback) ,第二個(gè)參數(shù)是初始值(initialValue)。
reduceRight 方法除了與 reduce 執(zhí)行方向相反外(從右往左),其他完全與其一致。
回調(diào)函數(shù)接收四個(gè)參數(shù):
- accumulator:MDN 上解釋為累計(jì)器,但我覺得不恰當(dāng),按我的理解它應(yīng)該是截至當(dāng)前元素,之前所有的數(shù)組元素被回調(diào)函數(shù)處理累計(jì)的結(jié)果。
- current:當(dāng)前被執(zhí)行的數(shù)組元素。
- currentIndex: 當(dāng)前被執(zhí)行的數(shù)組元素索引。
- sourceArray:原數(shù)組,也就是調(diào)用 reduce 方法的數(shù)組。
如果不傳入初始值,reduce 方法會(huì)從索引 1 開始執(zhí)行回調(diào)函數(shù),如果傳入初始值,將從索引 0 開始、并從初始值的基礎(chǔ)上累計(jì)執(zhí)行回調(diào)。
計(jì)算對(duì)象數(shù)組某一屬性的總和
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
對(duì)象數(shù)組的去重,并統(tǒng)計(jì)每一項(xiàng)重復(fù)次數(shù)
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 }, // ]
對(duì)象數(shù)組最大/最小值獲取
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 很強(qiáng)大,更多奇技淫巧推薦查看這篇《25個(gè)你不得不知道的數(shù)組reduce高級(jí)用法》
性能對(duì)比
說了這么多,那這些遍歷方法, 在性能上有什么差異呢?我們在 Chrome 瀏覽器中嘗試。我采用每個(gè)循環(huán)執(zhí)行10次,去除最大、最小值 取平均數(shù),降低誤差。
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
從打印結(jié)果可以看出,for 循環(huán)的速度最快,for ...of 循環(huán)最慢。
常用遍歷的終止、性能表格對(duì)比
最后,不同瀏覽器內(nèi)核 也會(huì)有些差異,有興趣的同學(xué)也可以嘗試一下。
對(duì)象遍歷
在對(duì)象遍歷中,經(jīng)常需要遍歷對(duì)象的鍵、值,ES5 提供了 for...in 用來遍歷對(duì)象,然而其涉及對(duì)象屬性的“可枚舉屬性”、原型鏈屬性等,下面將從 Object 對(duì)象本質(zhì)探尋各種遍歷對(duì)象的方法,并區(qū)分常用方法的一些特點(diǎn)。
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 原型鏈上擴(kuò)展的方法也被遍歷出來 for (const i in obj) { if (Object.prototype.hasOwnProperty.call(obj, i)) { console.log(i, ':', obj[i]); } } // name : a 不屬于自身的屬性將被 hasOwnProperty 過濾
小結(jié)
使用 for in 循環(huán)時(shí),返回的是所有能夠通過對(duì)象訪問的、可枚舉的屬性,既包括存在于實(shí)例中的屬性,也包括存在于原型中的實(shí)例。如果只需要獲取對(duì)象的實(shí)例屬性,可以使用 hasOwnProperty 進(jìn)行過濾。
使用時(shí),要使用(const x in a)而不是(x in a)后者將會(huì)創(chuàng)建一個(gè)全局變量。
for in 的循環(huán)順序,參考【JavaScript 權(quán)威指南】(第七版)6.6.1。
- 先列出名字為非負(fù)整數(shù)的字符串屬性,按照數(shù)值順序從最小到最大。這條規(guī)則意味著數(shù)組和類數(shù)組對(duì)象的屬性會(huì)按照順序被枚舉。
- 在列出類數(shù)組索引的所有屬性之后,在列出所有剩下的字符串名字(包括看起來像整負(fù)數(shù)或浮點(diǎn)數(shù)的名字)的屬性。這些屬性按照它們添加到對(duì)象的先后順序列出。對(duì)于在對(duì)象字面量中定義的屬性,按照他們在字面量中出現(xiàn)的順序列出。
- 最后,名字為符號(hào)對(duì)象的屬性按照它們添加到對(duì)象的先后順序列出。
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']
小結(jié)
用于獲取對(duì)象自身所有的可枚舉的屬性值,但不包括原型中的屬性,然后返回一個(gè)由屬性名組成的數(shù)組。
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']
小結(jié)
用于獲取對(duì)象自身所有的可枚舉的屬性值,但不包括原型中的屬性,然后返回一個(gè)由屬性值組成的數(shù)組。
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
小結(jié)
用于獲取對(duì)象自身所有的可枚舉的屬性值,但不包括原型中的屬性,然后返回二維數(shù)組。每一個(gè)子數(shù)組由對(duì)象的屬性名、屬性值組成??梢酝瑫r(shí)拿到屬性名與屬性值的方法。
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']
小結(jié)
用于獲取對(duì)象自身所有的可枚舉的屬性值,但不包括原型中的屬性,然后返回一個(gè)由屬性名組成的數(shù)組。
總結(jié)
我們對(duì)比了多種常用遍歷的方法的差異,在了解了這些之后,我們在使用的時(shí)候需要好好思考一下,就能知道那個(gè)方法是最合適的。歡迎大家糾正補(bǔ)充。
到此這篇關(guān)于JS中數(shù)組常用的循環(huán)遍歷的文章就介紹到這了,更多相關(guān)JS數(shù)組循環(huán)遍歷內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MutationObserver監(jiān)視對(duì)DOM?樹所做更改的功能妙用
這篇文章主要為大家介紹了MutationObserver監(jiān)視對(duì)DOM?樹所做更改的功能妙用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03Object.keys()、Object.values()、Object.entries()用法總結(jié)
本文主要介紹了Object.keys()、Object.values()、Object.entries()用法總結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04微信小程序個(gè)人中心的列表控件實(shí)現(xiàn)代碼
這篇文章主要介紹了微信小程序個(gè)人中心的列表控件實(shí)現(xiàn)代碼,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04js原生跨域_用script標(biāo)簽的簡單實(shí)現(xiàn)
下面小編就為大家?guī)硪黄猨s原生跨域_用script標(biāo)簽的簡單實(shí)現(xiàn)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-09-09javascript使用中為什么10..toString()正常而10.toString()出錯(cuò)呢
在JavaScript中為什么10..toString()正常,而10.toString()出錯(cuò)呢?這個(gè)問題一直困擾著我,所抽時(shí)間搜集整理下,曬出來與大家分享感興趣的朋友可以了解下,希望對(duì)你們有幫助2013-01-01基于bootstrap實(shí)現(xiàn)多個(gè)下拉框同時(shí)搜索功能
這篇文章主要為大家詳細(xì)介紹了基于bootstrap實(shí)現(xiàn)多個(gè)下拉框同時(shí)搜索功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07