【JS】830- 為什么不推薦用for...in遍歷數(shù)組

轉(zhuǎn)載自:沐碼小站
https://wintc.top/article/49
一、for...in引發(fā)的一個(gè)報(bào)錯(cuò)
兩年前寫的一個(gè)文章目錄生成插件vue-outline,一直用著沒出啥問題(本站的文章目錄也是用該插件生成的)。但是最近一個(gè)網(wǎng)友在使用的時(shí)候卻出現(xiàn)了異常報(bào)錯(cuò),異常代碼使用了一個(gè)for...in遍歷數(shù)組:
??for?(let?idx?in?selectors)?{
????let?elementList?=?dom.querySelectorAll(selectors[idx])
????elementList.forEach(element?=>?{
??????if?(element.__nav_except?||?element.offsetParent?===?null)?return
??????element.__nav_level?=?idx
????})
??}
代碼本意是,通過用戶給定的選擇器列表selectors確定哪些元素可以提取出來(lái)作為標(biāo)題,比如傳一個(gè)['h1', 'h3', 'div.title']。網(wǎng)友的使用方法完全正確,selectors傳遞的都是合法的選擇器,但是會(huì)出現(xiàn)以下報(bào)錯(cuò):

一個(gè)函數(shù)不是一個(gè)合法的選擇器?selectors里傳遞的都是選擇器。最后這位網(wǎng)友找到了原因,可能和for...in有關(guān)系,因?yàn)樗跀?shù)組的原型上添加了一些便捷的方法:

而for...in會(huì)遍歷出原型上的這些方法,這就導(dǎo)致在執(zhí)行前面的代碼時(shí),把一個(gè)函數(shù)作為參數(shù)傳遞給了querySelectorAll,導(dǎo)致報(bào)錯(cuò)!
二、for...in細(xì)節(jié)
for...in本身是Object的遍歷方法,JS中的數(shù)組也繼承自O(shè)bject,所以自然而然也能使用for...in遍歷出屬性。然而for...in有一些難以注意到的細(xì)節(jié),稍不注意就可能被坑。
1. 細(xì)節(jié)一:遍歷的屬性值是字符串,而不是數(shù)字!(相信初接觸JS的人都要被坑一次吧)
const?list?=?[1,?2,?3]
for?(let?i?in?list)?{
????console.log(i,?i?+?1,?typeof?i)
}
打印:
0?01?string
1?11?string
2?21?string
可以看到typeof i的返回值是“string”,這個(gè)最坑的地方在于我們通過下標(biāo)加減想取別的元素時(shí),就會(huì)出現(xiàn)異常,像上述輸出的i + 1一樣,并不是數(shù)字相加,而是字符串拼接!
2. 細(xì)節(jié)二:遍歷的是對(duì)象的枚舉屬性,包括自身屬性以及原型鏈上的屬性
const?obj?=?{
??a:?'value_a',
??b:?'value_b'
}
Object.prototype.c?=?'proto_value_c'
Object.defineProperty(obj,?'d',?{
??get?()?{?return?'value_d'?},
??enumerable:?false,
})
for?(let?key?in?obj)?{
??console.log(key,?obj[key])
}
輸出:
a?value_a
b?value_b
c?proto_value_c
可以看到,原型上的屬性c也打印出來(lái)了,但是通過Object.defineProperty定義的不可枚舉屬性d(enumerable: false)沒有被遍歷到。
3. 細(xì)節(jié)三:遍歷順序是對(duì)象屬性的枚舉順序,并不一定按數(shù)組的下標(biāo)順序遍歷
for...in的遍歷順序是枚舉順序,對(duì)于數(shù)組而言,規(guī)范并沒有約束各瀏覽器的實(shí)現(xiàn)。因此即便在一定范圍內(nèi)是按順序遍歷的,也應(yīng)該盡量不依賴for...in遍歷的順序。MDN文檔也明確指出,不建議使用for...in遍歷數(shù)組,特別是想按照索引順序遍歷的時(shí)候:

此外,因?yàn)橛邢∈钄?shù)組的存在,其實(shí)JS里的數(shù)組不一定是順序結(jié)構(gòu)存儲(chǔ)的。當(dāng)數(shù)組的鍵分布較為稀疏,為了充分節(jié)約空間,數(shù)組可能會(huì)退化為像對(duì)象一樣的哈希表存儲(chǔ)結(jié)構(gòu)。
因?yàn)閒or...in本身是對(duì)象的遍歷方法,并不適用于數(shù)組,對(duì)于數(shù)組,還是for...of、for循環(huán)、forEach等遍歷比較好。

回復(fù)“加群”與大佬們一起交流學(xué)習(xí)~
點(diǎn)擊“閱讀原文”查看 100+ 篇原創(chuàng)文章
