【JS】工作中的高频代码for循环,你真的了解吗?

336 阅读2分钟

image.png

在日常开发过程中,高频使用的语句如果for循环说自己是第二,则没人敢称第一。这篇文章我们来详细看下for循环在各个场景中的使用。

1.遍历普通数组

当需要用到break、continue或者return时,可以使用for( i=0 ... i++ )和for ... of,但是不能使用forEach

break和continue

let arr = [0,1,2,3, ,5]

for(let i = 0; i < arr.length; i ++) {
    if(arr[i] === 3) {
        break  // 0 1 2
        // continue  // 0 1 2 undefined 5
    }
    console.log(arr[i])
}
for(let item of arr) {
    if(item === 3) {
       break  // 0 1 2
       // continue  // 0 1 2 undefined 5 
    }
    console.log(item)
}

arr.forEach((item, index, arr) => {
    if(item === 3) {
        break  // 0 1 2 3 5
    }
    console.log(item)
})

函数return

let arr = [0,1,2,3, ,5]
function f(arr) {
    arr.forEach((item, index, arr) => {
        if(item === 3) {
            return  // 0 1 2 5
        }
    console.log(item)
    })
}
f(arr)

let arr = [0,1,2,3, ,5]
function f(arr) {
    for(let item of arr) {
        if(item === 3) {
            return  // 0 1 2
        }
    console.log(item)
    }
}

f(arr)

特点总结

  1. for( i=0 ... i++ )遍历数组的索引,for ... of遍历数组的元素,forEach可以同时遍历索引、元素和数组
  2. for( i=0 ... i++ )和for ... of可以被break和continue结束或中断循环,也可以通过return返回结束函数,forEeach则不受break和continue的影响,不能通过return返回结束函数
  3. for( i=0 ... i++ )和for ...of遇到元素为空仍会执行本次循环,而forEach遇到空元素会不执行本次循环

使用场景总结

  1. 如果需要return或者break,选for ... of 或 for( i=0 ... i++ )
  2. 如果需要index,但不需要return或者break, 选forEach 或 for( i=0 ... i++ )
  3. 如果需要index, 且需要return或者break, 选for( i=0 ... i++ )

2. this的指向问题

let arr = [0,1,2,3, ,5]

for(let i = 0; i < arr.length; i ++) {
    console.log(this) // window
}

for(let item of arr) {
    console.log(this) // window
}

arr.forEach((item, index, arr) => {
    console.log(this) // window
})

arr.forEach(function(item, index, arr) {
    console.log(this) // undefined
})

当forEach里面如果用的是普通函数,则是不能初始化this的,其他情况下均可以初始化this。

总结:forEach里不要使用this

3. 异步处理情况 async/await

用setTimeout模拟异步执行的方法

passOrFailed (i) {
  return new Promise((resolve) => {
    // 异步操作
    setTimeout(() => {
      console.log(`${i}成功`)
      resolve()
    }, 1000)
  })
},

在test ()函数里循坏遍历去调用,期望是第一个循环里的内容全部执行完,再去执行下一次循环

async test () {
  const arr = [1, 2, 3, 4, 5]
  for (let i = 0; i < arr.length; i++) {
    console.log(`${i}start`)
    await this.passOrFailed(i)
    console.log(`${i}end`)
  }
}

期望的结果是这样的

// 0start
// 0成功
// 0end
// 1start
// 1成功
// 1end
// ...

下面我们直接看下完整代码

3.1 for( i=0 ... i++ )

// a.vue
<script>
export default {
  methods: {
    passOrFailed (i) {
      return new Promise((resolve) => {
        // 异步操作
        setTimeout(() => {
          console.log(`${i}成功`)
          resolve()
        }, 1000)
      })
    },

    async test () {
      const arr = [1, 2, 3, 4, 5]
      for (let i = 0; i < arr.length; i++) {
        console.log(`${i}start`)
        await this.passOrFailed(i)
        console.log(`${i}end`)
      }
    }

  },

  mounted () {
    console.log('start!!!')
    this.test().then(() => { console.log('end!!!') })
  }
}
</script>

3.2 for ... of

// a.vue
<script>
export default {
  data () {
    return { }
  },
  methods: {
    passOrFailed (i) {
      return new Promise((resolve) => {
        // 异步操作
        setTimeout(() => {
          console.log(`${i}成功`)
          resolve()
        }, 1000)
      })
    },

    async test () {
      const arr = [1, 2, 3, 4, 5]
      for (const item of arr) {
        console.log(`${item}start`)
        await this.passOrFailed(item)
        console.log(`${item}end`)
      }
    }

  },

  mounted () {
    console.log('start!!!')
    this.test().then(() => { console.log('end!!!') })
  }
}
</script>

for( i=0 ... i++ )和for ... of的输出结果是一样的

image.png

3.3 forEach

如果像这样按照上面的写法直接改成forEach,编译会报错

// a.vue
async test () {
  const arr = [1, 2, 3, 4, 5]
  arr.forEach(item => {
    console.log(`${item}start`)
    await this.passOrFailed(item)
    console.log(`${item}end`)
  })
}

我们需要改成这样的写法

// a.vue
<script>
export default {
  data () {
    return { }
  },
  methods: {
    passOrFailed (i) {
      return new Promise((resolve) => {
        // 异步操作
        setTimeout(() => {
          console.log(`${i}成功`)
          resolve()
        }, 1000)
      })
    },

    test () {
      const arr = [1, 2, 3, 4, 5]
      arr.forEach(async item => {
        console.log(`${item}start`)
        await this.passOrFailed(item)
        console.log(`${item}end`)
      })
    }
  },

  mounted () {
    console.log('start!!!')
    this.test()
    console.log('end!!!')
  }
}
</script>

得到的结果和我们逻辑上期望的不一样的

image.png

所以当涉及到异步操作时,尽量不要使用forEach

4. 总结

不同场景下for循环的使用情况总结如下

image.png

我们看到最原始的for( i=0 ... i++ )是使用于所有场景的,但是代码量会相对多一点,forEach写起来代码量是比较少的,也更直观,但是使用的局限性也比较大,注意不是所有场景都可以用的哦。还是要根据不同的场景使用不同的循坏。

如果觉得文章对你有用,就点个赞再走吧,笔芯~