一文完全弄懂 for forEach for-in for-of 的区分

基础语法

下面列出了这几个遍历语法划定规矩:

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 中一切的数组都是对象,这意味着你能够给数组增加字符串属性:

array = ['a', 'b', 'c']

array.test = 'testing'
console.log(array) // [ 'a', 'b', 'c', test: 'testing' ]

假如打印,那末这个 test 也会被打印出来

在浏览器中,运用 console.table(array) 打印这个数组能够看到,这个对象中 test 为 index,testing 为 value;其他数组项的 index 值均为数字

《一文完全弄懂 for forEach for-in for-of 的区分》

上述提到的几个遍历要领中只要 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 遍历出来

现实运用的题目

在 JSON 中是不支持如许的空值的,假如在 parse 要领挪用时传入的 JSON 字符串数据含有空值,会报错:

JSON.parse('["a", , "c"]')
// 所以发起运用 for-of 或 for 轮回举行遍历,由于假如
  • stringify 要领挪用时,空值会被转为 null 非空值或 undefined
  • 准确的做法应该是坚持 undefined,遍历运用 for-of 或 for 轮回

发起运用 for-of

要领 this 指向的上下文

在 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/Await

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)
    })
})()}

参考:

迎接定阅我的民众号:

《一文完全弄懂 for forEach for-in for-of 的区分》

    原文作者:JS菌
    原文地址: https://segmentfault.com/a/1190000018340362
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞