JavaScript中遍歷數(shù)組和對象的幾種常用方法(轉載)

數(shù)組和對象在各種編程語言中都充當著至關重要的角色,本篇文章給大家介紹一下JavaScript中常用數(shù)組遍歷渔工、對象遍歷的方法和各方法間的差異,以及使用時的注意事項。

image

數(shù)組遍歷

隨著 JS 的不斷發(fā)展旷档,截至 ES7 規(guī)范已經有十多種遍歷方法。下面按照功能類似的方法為一組歇拆,來介紹數(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  10 11
});

小結

  • 三者都是基本的由左到右遍歷數(shù)組
  • forEach 無法跳出循環(huán)厂庇;for 和 for ..of 可以使用 break 或者 continue 跳過或中斷。
  • for ...of 直接訪問的是實際元素输吏。for 遍歷數(shù)組索引权旷,forEach 回調函數(shù)參數(shù)更豐富,元素评也、索引炼杖、原數(shù)組都可以獲取灭返。
  • for ...of 與 for 如果數(shù)組中存在空元素,同樣會執(zhí)行坤邪。

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

小結

  • 二者都是用來做數(shù)組條件判斷的,都是返回一個布爾值
  • 二者都可以被中斷
  • some 若某一元素滿足條件艇纺,返回 true怎静,循環(huán)中斷;所有元素不滿足條件黔衡,返回 false蚓聘。
  • every 與 some 相反,若有益元素不滿足條件盟劫,返回 false夜牡,循環(huán)中斷;所有元素滿足條件侣签,返回 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 },
// ]

小結

  • 二者都是生成一個新數(shù)組影所,都不會改變原數(shù)組(不包括遍歷對象數(shù)組是蹦肴,在回調函數(shù)中操作元素對象)
  • 二者都會跳過空元素。有興趣的同學可以自己打印一下
  • map 會將回調函數(shù)的返回值組成一個新數(shù)組猴娩,數(shù)組長度與原數(shù)組一致阴幌。
  • filter 會將符合回調函數(shù)條件的元素組成一個新數(shù)組,數(shù)組長度與原數(shù)組不同卷中。
  • map 生成的新數(shù)組元素是可自定義矛双。
  • filter 生成的新數(shù)組元素不可自定義,與對應原數(shù)組元素一致仓坞。

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 // '底部導航';

小結

  • 二者都是用來查找數(shù)組元素。
  • find 方法返回數(shù)組中滿足 callback 函數(shù)的第一個元素的值无埃。如果不存在返回 undefined徙瓶。
  • findIndex 它返回數(shù)組中找到的元素的索引,而不是其值嫉称,如果不存在返回 -1侦镇。

reduce、reduceRight

reduce 方法接收兩個參數(shù)织阅,第一個參數(shù)是回調函數(shù)(callback) 壳繁,第二個參數(shù)是初始值(initialValue)。

reduceRight 方法除了與reduce執(zhí)行方向相反外(從右往左),其他完全與其一致闹炉。

回調函數(shù)接收四個參數(shù):

  • accumulator:MDN 上解釋為累計器蒿赢,但我覺得不恰當,按我的理解它應該是截至當前元素渣触,之前所有的數(shù)組元素被回調函數(shù)處理累計的結果羡棵。
  • current:當前被執(zhí)行的數(shù)組元素。
  • currentIndex: 當前被執(zhí)行的數(shù)組元素索引嗅钻。
  • sourceArray:原數(shù)組皂冰,也就是調用 reduce 方法的數(shù)組。

如果不傳入初始值养篓,reduce 方法會從索引 1 開始執(zhí)行回調函數(shù)秃流,如果傳入初始值,將從索引 0 開始柳弄、并從初始值的基礎上累計執(zhí)行回調舶胀。

計算對象數(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

對象數(shù)組的去重,并統(tǒng)計每一項重復次數(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 },
// ]

對象數(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 很強大语御,更多奇技淫巧推薦查看這篇《25個你不得不知道的數(shù)組reduce高級用法》

性能對比

說了這么多峻贮,那這些遍歷方法, 在性能上有什么差異呢应闯?我們在 Chrome 瀏覽器中嘗試。我采用每個循環(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

從打印結果可以看出骨田,for 循環(huán)的速度最快,for of 循環(huán)最慢

常用遍歷的終止声怔、性能表格對比

|
| 是否可終止 |
|
|
|
| :-: | :-- | :-: | :-- | :-: |
| **** | break | continue | return | 性能(ms) |
| for | 終止 ? | 跳出本次循環(huán) ? | ? | 2.42 |
| forEach | ? | ? | ? | 3.12 |
| map | ? | ? | ? | 3.74 |
| for of | 終止 ? | 跳出本次循環(huán) ? | ? | 6.33 |
| some | ? | ? | return true ? | 2.78 |
| every | ? | ? | return false ? | 2.75 |

最后态贤,不同瀏覽器內核 也會有些差異,有興趣的同學也可以嘗試一下。

對象遍歷

在對象遍歷中醋火,經常需要遍歷對象的鍵悠汽、值,ES5 提供了 for...in 用來遍歷對象芥驳,然而其涉及對象屬性的“可枚舉屬性”柿冲、原型鏈屬性等,下面將從 Object 對象本質探尋各種遍歷對象的方法兆旬,并區(qū)分常用方法的一些特點假抄。

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 循環(huán)時,返回的是所有能夠通過對象訪問的、可枚舉的屬性宿饱,既包括存在于實例中的屬性熏瞄,也包括存在于原型中的實例。如果只需要獲取對象的實例屬性谬以,可以使用 hasOwnProperty 進行過濾巴刻。

使用時,要使用(const x in a)而不是(x in a)后者將會創(chuàng)建一個全局變量蛉签。

for in 的循環(huán)順序胡陪,參考【JavaScript 權威指南】(第七版)6.6.1。

  • 先列出名字為非負整數(shù)的字符串屬性碍舍,按照數(shù)值順序從最小到最大柠座。這條規(guī)則意味著數(shù)組和類數(shù)組對象的屬性會按照順序被枚舉。
  • 在列出類數(shù)組索引的所有屬性之后片橡,在列出所有剩下的字符串名字(包括看起來像整負數(shù)或浮點數(shù)的名字)的屬性妈经。這些屬性按照它們添加到對象的先后順序列出。對于在對象字面量中定義的屬性捧书,按照他們在字面量中出現(xiàn)的順序列出吹泡。
  • 最后,名字為符號對象的屬性按照它們添加到對象的先后順序列出经瓷。

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']

小結

用于獲取對象自身所有的可枚舉的屬性值爆哑,但不包括原型中的屬性,然后返回一個由屬性名組成的數(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']

小結

用于獲取對象自身所有的可枚舉的屬性值揭朝,但不包括原型中的屬性,然后返回一個由屬性值組成的數(shù)組色冀。

Object.entries

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

小結

用于獲取對象自身所有的可枚舉的屬性值潭袱,但不包括原型中的屬性,然后返回二維數(shù)組锋恬。每一個子數(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']

小結

用于獲取對象自身所有的可枚舉的屬性值,但不包括原型中的屬性癣防,然后返回一個由屬性名組成的數(shù)組蜗巧。

總結

我們對比了多種常用遍歷的方法的差異,在了解了這些之后蕾盯,我們在使用的時候需要好好思考一下幕屹,就能知道那個方法是最合適的蓝丙。歡迎大家糾正補充。

本文轉載自:https://www.php.cn/js-tutorial-478675.html

更多編程相關知識望拖,請訪問:編程視頻C斐尽!

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末说敏,一起剝皮案震驚了整個濱河市鸥跟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盔沫,老刑警劉巖医咨,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異架诞,居然都是意外死亡拟淮,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門谴忧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來很泊,“玉大人,你說我怎么就攤上這事沾谓∥欤” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵均驶,是天一觀的道長昏兆。 經常有香客問我,道長辣恋,這世上最難降的妖魔是什么亮垫? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮伟骨,結果婚禮上,老公的妹妹穿的比我還像新娘燃异。我一直安慰自己携狭,他們只是感情好,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布回俐。 她就那樣靜靜地躺著逛腿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪仅颇。 梳的紋絲不亂的頭發(fā)上单默,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機與錄音忘瓦,去河邊找鬼搁廓。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的境蜕。 我是一名探鬼主播蝙场,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼粱年!你這毒婦竟也來了售滤?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤台诗,失蹤者是張志新(化名)和其女友劉穎完箩,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拉队,經...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡弊知,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了氏仗。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吉捶。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖皆尔,靈堂內的尸體忽然破棺而出呐舔,到底是詐尸還是另有隱情,我是刑警寧澤慷蠕,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布珊拼,位于F島的核電站,受9級特大地震影響流炕,放射性物質發(fā)生泄漏澎现。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一每辟、第九天 我趴在偏房一處隱蔽的房頂上張望剑辫。 院中可真熱鬧,春花似錦渠欺、人聲如沸妹蔽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽胳岂。三九已至,卻和暖如春舔稀,著一層夾襖步出監(jiān)牢的瞬間乳丰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工内贮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留产园,地道東北人汞斧。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像淆两,于是被迫代替她去往敵國和親断箫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內容