透过 for in 和 for of 的区别,你看到了什么

简介: 透过 for in 和 for of 的区别,你看到了什么

简介

经常看到有人问 for infor of 的区别,基本网上去搜几篇文章也都能窥探一二, 但是当我真正使用下来,发现里面其实还是有很多问题,比如:

  • 为什么有了 for 循环,还会有 for infor of
  • 为什么 for infor of 都能遍历数组?
  • 为什么 for of 不能遍历对象

当我尝试去把这些问题一一解开的时候,发现事情并不是那么简单。下面进入正题。

for in 和 for of 基本介绍

要了解 for infor of,我们需要先看看 for infor of 的历史,for injs 第一个版本就实现了,和 for 循环是一起出现的; 而 for of 的出现是在 js 大更新的 ES6 时期。 需要说明的是早期 js 还没有现在这么复杂,对象和数组已经能完全满足我们的开发,所以早期将 for 循环用于遍历数组,而 for in 用于遍历对象。 各司其职,就已经足够了。 而 for of 是在 ES6 在新增的,与 for of 同时出现的还有 MapSet 这些新的数据存储结构, 已有的 for 循环显然满足不了各种新结构的遍历功能,而 for of 的出现弥补了新的数据结构的遍历功能缺失。

for in 的基本使用

当我们拥有一个对象的时候,我们有时候需要知道这个对象有哪些属性,或者统计对象的属性个数的时候就可以使用 for in

// for in 遍历一个对象
const obj = { a: 'string', b: 1, c: false }
for (const key in obj) {
  console.log(key, obj[key])
}
// 结果如下:
// a string
// b 1
// c false
复制代码

for of 的基本使用

// for of 遍历一个 Map
const map = new Map([['a', 'string'], ['b', 1], ['c', false]])
for (const [key, value] of map) {
  console.log(key, value)
}
// 结果如下:
// a string
// b 1
// c false
复制代码

为什么 for in 能够遍历数组?

前面我们提到了 for in 是用来遍历对象的,那为什么 for in 也能遍历数组呢? 这里其实就不得不提一嘴了,js 的数组结构其实不是真正的数组结构, 这个其实不难发现,你打开任何一个介绍数据结构的书籍里面都会提到,数组是一个连续的存储空间。 所以数组的长度一定是固定的,而且必须存储统一类型的数据。而 js 的数组其实是基于对象封装的, 所以你可以理解为在 js 里,数组就是一个实现了数组方法的对象。所以 for in 能遍历数组就一点也不奇怪了。

为什么 for of 不能遍历对象

在开头就讲到了,ES6 新增了新的数据结构,比如 Map,而且考虑到 js 的火热,那么很有可能还会有更多的数据结构出现, 早期只有对象和数组,for 循环和 for in 也不是那么难理解,但是考虑到后续的拓展性,我们需要一种新的迭代方法, 它最好能够支持所有数据结构的遍历。听起来有点困难,但其实这是一个很简单的事情,设计模式里面就提到了我们的迭代器模式, 迭代器模式的核心思想就是旨在不暴露数据结构的情况下能够遍历集合中的所有元素。 只不过由于迭代器模式是在是太重要了,所以你可能都注意不到它。大家在看 for of 的使用介绍中, 都会看到这么一句话,for of 只能用来遍历可迭代对象。这句话就说明了 for of 遍历的其实不是我们的数据结构,而是数据结构提供的迭代器。 那么 js 中哪些数据结构提供了迭代器呢?根据 MDN 的数据, 已知的有ArrayMapSetStringTypedArrayarguments 等,就是不包含对象。

给对象实现个迭代器

刚刚说了 for of 遍历的是数据结构提供的迭代器,既然对象没有,那我们尝试实现一个看看:

// 给对象添加迭代器
Object.prototype[Symbol.iterator] = function() {
  const values = Object.values(this)
  let index = 0
  return {
    next() {
      if (index < values.length) {
        return {
          value: values[index++],
          done: false
        }
      }
      return {
        value: undefined,
        done: true
      }
    }
  }
}
const obj = { a: 'string', b: 1, c: false }
// 测试一下
for (const val of obj) {
  console.log(val)
}
// string
// 1
// false
// 完美运行!
复制代码

结束

快乐的时间总是短暂,这片文章到这里就结束了。但是以后再有人问你 for infor of 的区别,我可不允许你不知道了啊!

大厂面试题分享 面试题库

前后端面试题库 (面试必备) 推荐:★★★★★

地址:前端面试题库  web前端面试题库 VS java后端面试题库大全

相关文章
透过现象看创本质的能力-从忒休斯之船到系统论
透过现象看创本质的能力-从忒休斯之船到系统论
|
5月前
|
网络协议 网络架构
动图 | 6张图让你秒懂“ARP中间人攻击”原理,堪称史诗级解释!
动图 | 6张图让你秒懂“ARP中间人攻击”原理,堪称史诗级解释!
233 0
|
7月前
|
传感器 存储 编解码
数码相机背后的像素秘密:静态与动态的真相
这篇文章探讨了数码摄影中“动态像素”和“静态像素”的概念。像素是图像质量的关键因素,而CCD或CMOS传感器负责将光信号转化为数字图像。RGB差值补偿算法用于恢复色彩,但牺牲了部分分辨率。所谓“动态像素”更多是营销术语,而非技术标准,它反映了拍照和录像时因硬件限制和处理需求不同而产生的差异。随着技术进步,硬件编码器的引入已显著提升视频处理能力,使得高清摄影和视频录制变得更加普遍。理解这些原理有助于消费者做出更明智的设备选择。
|
7月前
|
数据采集 自然语言处理 数据挖掘
一文搞懂:【VC++技术杂谈005】如何与程控仪器通过GPIB接口进行通信
一文搞懂:【VC++技术杂谈005】如何与程控仪器通过GPIB接口进行通信
184 0
|
7月前
|
Java
Java面向对象特征(一)----- 封装
Java面向对象特征(一)----- 封装
|
8月前
|
存储 前端开发 调度
揭秘计算机内部通信:探秘数据、地址与控制信号的奥秘
本文深入剖析计算机总线的核心概念,探讨数据、地址和控制信号的传输,揭示了计算机内部各组件间通信的精妙机制。了解总线系统,将带你走进计算机硬件的奥秘,深化对计算机内部工作原理的理解。
289 1
|
安全 测试技术 数据安全/隐私保护
带你读《思科软件定义访问 : 实现基于业务意图的园区网络》第二章软件定义访问体系结构2.6(二)
《思科软件定义访问 : 实现基于业务意图的园区网络》第二章软件定义访问体系结构2.6
带你读《思科软件定义访问 : 实现基于业务意图的园区网络》第二章软件定义访问体系结构2.6(二)
|
机器学习/深度学习 安全 测试技术
带你读《思科软件定义访问 : 实现基于业务意图的园区网络》第二章软件定义访问体系结构2.5(二)
带你读《思科软件定义访问 : 实现基于业务意图的园区网络》第二章软件定义访问体系结构2.5
带你读《思科软件定义访问 : 实现基于业务意图的园区网络》第二章软件定义访问体系结构2.5(二)
|
边缘计算 运维 安全
带你读《思科软件定义访问 : 实现基于业务意图的园区网络》第二章软件定义访问体系结构2.3(六)
带你读《思科软件定义访问 : 实现基于业务意图的园区网络》第二章软件定义访问体系结构2.3
带你读《思科软件定义访问 : 实现基于业务意图的园区网络》第二章软件定义访问体系结构2.3(六)
|
运维 BI 定位技术
带你读《思科软件定义访问 : 实现基于业务意图的园区网络》第二章软件定义访问体系结构2.5(六)
带你读《思科软件定义访问 : 实现基于业务意图的园区网络》第二章软件定义访问体系结构2.5
带你读《思科软件定义访问 : 实现基于业务意图的园区网络》第二章软件定义访问体系结构2.5(六)