博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一文彻底弄懂 for forEach for-in for-of 的区别
阅读量:5908 次
发布时间:2019-06-19

本文共 3545 字,大约阅读时间需要 11 分钟。

基本语法

下面列出了这几个遍历语法规则:

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 值均为数字

20190228105221.png

上述提到的几个遍历方法中只有 for-in 循环才能够打印出这个键值对:

for (const key in array) {    console.log(array[key])}

实际应用的问题

通常情况下,不建议使用 for-in 来遍历数组,除非你知道这个数组对象中没有这样的属性

数组空项

假设要遍历的数组张这样:array = ['a', , 'c']

// a undefined cfor (let index = 0; index < array.length; index++) {    const element = array[index]    console.log(element) // 没有跳过空值}// a carray.forEach(element => {    console.log(element) // 跳过空值})// a cfor (const key in array) {    console.log(array[key]) // 跳过空值}// a undefined cfor (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)    })})()}

参考:

欢迎订阅我的公众号:

5c778bbe7d90d.png

转载地址:http://pqvpx.baihongyu.com/

你可能感兴趣的文章
(六)模板渲染
查看>>
Cisco路由器安全配置
查看>>
我的友情链接
查看>>
半天打造小型万能OA办公系统, 靠的就是万能表单提交 + 轻量级工作流审批组件...
查看>>
VM的彻底删除
查看>>
我的友情链接
查看>>
CSS技巧笔记
查看>>
我的友情链接
查看>>
WP移动设备压缩与解压控件Xceed Zip for .NET Compact Framework控件下载及详细介绍使用方法...
查看>>
在右下角弹出通知窗口
查看>>
android 镜像文件打包和解压
查看>>
proc文件系统探索 之 根目录下的文件[六]
查看>>
bootstrap49-Bootstrap 分割的按钮下拉菜单
查看>>
搭建ICINGA监控
查看>>
LInux远程文件传输效率工具:lrzsz
查看>>
Java_String的操作
查看>>
如何成为一名“***”?
查看>>
ActionContextCleanUp
查看>>
First iOS App_Inspecting the View Controller and Its View
查看>>
Kali-linux安装之后的简单设置
查看>>