下面列出了這幾個遍歷語法規則:javascript
for (let index = 0; index < array.length; index++) {
const element = array[index]
// ...
}
array.forEach(element => {
// ...
})
for (const key in array) {
// ...
}
for (const iterator of array) {
// ...
}
複製代碼
在 JavaScript 中全部的數組都是對象,這意味着你能夠給數組添加字符串屬性:html
array = ['a', 'b', 'c']
array.test = 'testing'
console.log(array) // [ 'a', 'b', 'c', test: 'testing' ]
複製代碼
若是打印,那麼這個 test 也會被打印出來java
在瀏覽器中,使用 console.table(array)
打印這個數組能夠看到,這個對象中 test 爲 index,testing 爲 value;其餘數組項的 index 值均爲數字編程
上述提到的幾個遍歷方法中只有 for-in 循環纔可以打印出這個鍵值對:數組
for (const key in array) {
console.log(array[key])
}
複製代碼
一般狀況下,不建議使用 for-in 來遍歷數組,除非你知道這個數組對象中沒有這樣的屬性瀏覽器
假設要遍歷的數組張這樣:array = ['a', , 'c']
異步
// a undefined c
for (let index = 0; index < array.length; index++) {
const element = array[index]
console.log(element) // 沒有跳過空值
}
// a c
array.forEach(element => {
console.log(element) // 跳過空值
})
// a c
for (const key in array) {
console.log(array[key]) // 跳過空值
}
// a undefined c
for (const iterator of array) {
console.log(iterator) // 沒有跳過空值
}
複製代碼
上面幾個遍歷方法,只有 forEach 和 for-in 遍歷會跳過空值,值得注意的是,若是空值明確設置爲 undefined 如 ['a', undefined, 'c']
那麼全部遍歷方法都可以將 undefined 遍歷出來async
在 JSON 中是不支持這樣的空值的,若是在 parse 方法調用時傳入的 JSON 字符串數據含有空值,會報錯:異步編程
JSON.parse('["a", , "c"]')
// 因此建議使用 for-of 或 for 循環進行遍歷,由於若是
複製代碼
建議使用 for-of函數
在 forEach 中須要傳入一個函數,這個函數的 this 指向因語法形式而變化:
for (let index = 0; index < array.length; index++) {
const element = array[index]
console.log(this) // {}
}
array.forEach(function (element) {
console.log(this) // undefined
})
array.forEach(element => {
console.log(this) // {}
})
for (const key in array) {
console.log(this) // {}
}
for (const iterator of array) {
console.log(this) // {}
}
複製代碼
上述遍歷寫法,只有 forEach 在傳入非箭頭函數的時候會出現不一致的狀況
建議使用箭頭函數
async 異步編程中 forEach 則不會按照預期執行,以下:
// a undefined c
{(async () => {
for (const iterator of array) {
const result = await new Promise(res => setTimeout(() => { res(iterator) }, 1000))
console.log(result)
}
})()}
// a c
{(async () => {
for (const key in array) {
const result = await new Promise(res => setTimeout(() => { res(array[key]) }, 1000))
console.log(result)
}
})()}
// a undefined c
{(async () => {
for (let index = 0; index < array.length; index++) {
const result = await new Promise(res => setTimeout(() => { res(array[index]) }, 1000))
console.log(result)
}
})()}
// 語法錯誤
{(async () => {
array.forEach(element => {
const result = await new Promise(res => setTimeout(() => { res(element) }, 1000))
console.log(result)
})
})()}
複製代碼
按照上述寫法 forEach 會報錯,首先看一下 forEach 的原理:
本質上 forEach 就像一個 for 循環的包裝:
Array.prototype.forEach = function (callback) {
for (let index = 0; index < this.length; index++) {
callback(this[index], index, this)
}
}
複製代碼
若是按照上述寫法,那麼在回調函數內部調用 await 須要這個回調函數自己也是 async 函數,所以改成以下寫法:
// 語法錯誤
{(async () => {
array.forEach(async element => {
const result = await new Promise(res => setTimeout(() => { res(element) }, 1000))
console.log(result)
})
})()}
複製代碼
按照這樣寫法,forEach 最後會變成並行執行,而非串行。
所以建議使用 for-of 循環
或者建立一個 forEachAwait 方法:
async function forEachAwait(arr, cb) {
for (let index = 0; index < array.length; index++) {
await cb(arr[index], index, arr)
}
}
// a undefined c
{(async () => {
forEachAwait(array, async (elem) => {
const result = await new Promise(res => setTimeout(() => { res(elem) }, 1000))
console.log(result)
})
})()}
複製代碼
歡迎訂閱個人公衆號: