Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >for...of循环的使用

for...of循环的使用

作者头像
kai666666
发布于 2024-07-11 10:52:50
发布于 2024-07-11 10:52:50
34500
代码可运行
举报
文章被收录于专栏:橙光笔记橙光笔记
运行总次数:0
代码可运行

for…of语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。 – MDN

基本使用

for…of的基本使用比较简单:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 遍历数组
let array = ['a', 'b', 'c'];

for (let value of array) {
  console.log(value); // 分别打印 'a' 'b' 'c'
}

// 遍历字符串
let str = "abc";

for (let value of str) {
  console.log(value); // 分别打印 'a' 'b' 'c'
}

// 遍历Map
let map = new Map([["a", 1], ["b", 2], ["c", 3]]);

for (let value of map) {
  console.log(value); // 分别打印 ["a", 1] ["b", 2] ["c", 3]
}

// 遍历Set
let set = new Set(['a', 'a', 'b', 'c', 'b', 'c']);

for (let value of set) {
  console.log(value); // 分别打印 'a' 'b' 'c'
}

// 遍历arguments
(function() {
  for (let argument of arguments) {
    console.log(argument); // 分别打印 'a' 'b' 'c'
  }
})('a', 'b', 'c');

可迭代对象

for…of的语法比较简单,上面我们遍历了这么多数据,现在我们使用for…of遍历一下对象:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let object = {
  a: 1,
  b: 2,
  c: 3,
}
for (let value of object) {
  console.log(value); // 报错:Uncaught TypeError: object is not iterable
}

结果很不幸,使用for…of遍历对象报错了。为什么报错了,报错的错误提示写的很清楚,因为object对象不是可迭代的,也就是说它不是可迭代对象

这里遇到一个新的名词,什么是可迭代对象呢?

要成为可迭代对象, 这个对象必须实现@@iterator方法,并且该方法返回一个符合迭代器协议的对象

这里有2个问题,第一怎么去实现一个@@iterator方法?看到@@xxx这样的方法,想都不用想就是指[Symbol.xxx]方法,这里也就是一个方法的key是[Symbol.iterator]就可以了,比如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let object = {
  a: 1,
  b: 2,
  c: 3,
  [Symbol.iterator]: function() {}
}

第二个问题什么是符合迭代器协议的对象?首先迭代器协议的对象是一个对象,这个对象有一个next方法,这个next方法每次调用有会返回一个对象,这个返回的对象又有一个done属性和一个value属性。其中done属性表示是否完成,如果是true则表示完成,false或者不写则表示没有完成;value表示值,也就是for…of循环时每次使用的值,如果done为true时候则可以不写。举个可迭代对象的例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let loop10 = {
  [Symbol.iterator]: function() {
    let i = 0

    return {
      next: function() {
        return {
          value: i++,
          done: i > 10
        }
      }
    }
  }
}

for (let value of loop10) {
  console.log(value); // 分别打印 0 1 2 3 4 5 6 7 8 9
}

迭代器协议的对象也可以自己调用着玩玩:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let iterator = loop10[Symbol.iterator]();
iterator.next(); // 返回 {value: 0, done: false}
iterator.next(); // 返回 {value: 1, done: false}
iterator.next(); // 返回 {value: 2, done: false}

当然迭代器协议的对象不仅仅只能用在for-of循环中,也可以用在数组的解构上:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let arr = [...loop10]; // arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

可迭代对象与generator函数

当我们看到一个个可迭代对象的next方法,再看看一个个的{value: 0, done: false}这种符合迭代器协议的对象,这时不想跟generator没点关系都不行了,没错generator函数返回的正是可迭代对象。我们先使用常规方法实现一下对象的for…of遍历。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let object = {
  a: 1,
  b: 2,
  c: 3,
  [Symbol.iterator]: function() {
    let keys = Object.keys(this);
    let i = 0

    return {
      next: function() {
        return {
          value: keys[i++],
          done: i > keys.length
        }
      }
    }
  }
}
for (let value of object) {
  console.log(value); // 分别打印 'a' 'b' 'c'
}

使用generator函数可以简化上述步骤:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let object = {
  a: 1,
  b: 2,
  c: 3,
  [Symbol.iterator]: function *() {
    let keys = Object.keys(this)
    for (let i = 0; i < keys.length; i++) {
      yield keys[i]
    }
  }
}
for (let value of object) {
  console.log(value); // 分别打印 'a' 'b' 'c'
}

是不是很方便?这里偷偷告诉你一个小秘密:generator函数调用后的对象也可以用在for…of上

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let loop10Gen = function *() {
  for (let i = 0; i < 10; i++) {
    yield i
  }
}

// 注意这里是loop10Gen() 而不是loop10Gen
for (const value of loop10Gen()) {
  console.log(value); // 分别打印 0 1 2 3 4 5 6 7 8 9
}

上面不是说了,可迭代对象要实现一个@@iterator方法,这里实现了吗?没错,这里还真实现了!你可以试试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let itarator = loop10Gen();
itarator[Symbol.iterator]() === itarator; // 返回true

于是我们就得到一个比较绕的真理:generator调用后的对象,既是可迭代对象,也是符合迭代器协议的对象

for…of与for…in的区别

  1. for…in遍历的是对象的可枚举属性,而for…of语句遍历的是可迭代对象所定义要迭代的数据。

由于for…in遍历的是对象的可枚举属性,所以对于数组来说打印的是键,而不是值:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let array = ['a', 'b', 'c'];

for (const value in array) {
  console.log(value); // 分别打印 '0' '1' '2'
}

for (const value of array) {
  console.log(value); // 分别打印 'a' 'b' 'c'
}
  1. for…in会遍历对象原型和原型链上的可枚举的属性。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let array = ['a', 'b', 'c'];

Object.prototype.formObject = true;
Array.prototype.formArray = true;
array.hello = 'world'


for (const value in array) {
  console.log(value); // 分别打印 0 1 2 hello formArray formObject
}

for (const value of array) {
  console.log(value); // 分别打印 'a' 'b' 'c'
}

通常为了避免for…in遍历原型和原型链上无关的可枚举属性,使用Object.hasOwnProperty()方法来判断:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let array = ['a', 'b', 'c'];

Object.prototype.formObject = true;
Array.prototype.formArray = true;
array.hello = 'world'

for (const value in array) {
  if (Object.hasOwnProperty.call(array, value)) {
    console.log(value); // 分别打印 0 1 2 hello
  }
}

for (const value of array) {
  console.log(value); // 分别打印 'a' 'b' 'c'
}

可迭代对象的return方法

可迭代对象除了next方法外还有return方法,主要用在循环中断的时候会调用,比如是用break关键字、或者抛出一个Error:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let loop10 = {
  [Symbol.iterator]: function() {
    let i = 0

    return {
      next: function() {
        return {
          value: i++,
          done: i > 10
        }
      },
      return: function() {
        console.log('return调用了~~')
        return { done: true };
      }
    }
  }
}

for (let value of loop10) {
  console.log(value); // 分别打印 0 1 2 3
  if (value === 3) {
    break; // 打印 'return调用了~~'
  }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-06-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Iterator与Generator
Iterator 提供了一种统一的接口机制,为各种不同数据结构提供统一的访问机制。定义 Iterator 就是提供一个具有 next() 方法的对象,每次调用 next() 都会返回一个结果对象,该结果对象有两个属性,value 表示当前的值,done 表示遍历是否结束。
闻说社
2022/08/19
4420
可以迭代大部分数据类型的 for…of 为什么不能遍历普通对象?
我们知道,ES6 中引入 for...of 循环,很多时候用以替代 for...in 和 forEach() ,并支持新的迭代协议。for...of 允许你遍历 Array(数组), String(字符串), Map(映射), Set(集合),TypedArray(类型化数组)、arguments、NodeList对象、Generator等可迭代的数据结构等。for...of语句在可迭代对象上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。
coder_koala
2020/12/17
1.3K0
可以迭代大部分数据类型的 for…of 为什么不能遍历普通对象?
ES6中的Iterator 和for of循环
迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺序访问其中的每个元素。
青梅煮码
2023/02/18
9060
一文彻底搞懂迭代器与生成器函数
迭代器和生成器在前端业务里经常有用到,但是可能感受不太明显。特别是生成器,在react中如果你有用过redux中间件redux-saga那么你一定对生成器很熟悉。
Maic
2022/08/29
6200
一文彻底搞懂迭代器与生成器函数
迭代器与生成器
迭代器我们经常使用,尤其是遍历数组时,比如 forEach 方法、map 方法。这些方法可以顺序访问数组中的各个元素,而且不需要暴露该对象的内部表示。例如下面的 map 方法,会将一个数组的每一个元素加一。
多云转晴
2020/04/08
5500
迭代器与生成器
前端高频手写题自测,你能做出几道
输入字符串s,以及其重复的次数,输出重复的结果,例如输入abc,2,输出abcabc。
helloworld1024
2022/11/01
5060
重读 ES6 标准入门(第3版)
仅将自己的理解做整理、归类并结合实际遇到的问题做记录,更推荐阅读 ECMAScript 6 入门。
掘金安东尼
2024/01/28
2060
es6 -- Iterator 和 for...of 循环
JavaScript 原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6 又添加了Map和Set。这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是Map,Map的成员是对象。这样就需要一种统一的接口机制,来处理所有不同的数据结构。
小蔚
2019/09/11
8140
迭代器与 for of的使用和原理
看着很简单,但是再回顾这段代码,实际上我们仅仅是需要数组中元素的值,但是却需要提前获取数组长度,声明索引变量等,尤其当多个循环嵌套的时候,更需要使用多个索引变量,代码的复杂度就会大大增加,比如我们使用双重循环进行去重:
ConardLi
2019/05/23
1.6K0
异步解决方案补充
接着昨天讲,四种异步解决方案前两种回调函数和promise昨天讲过了,今天只是补充说明另外两种解决方案。那讲之前肯定少不了我们要明确一下同步和异步的概念,这里咱找了一个更官方的解释来让我们更加的通俗易懂。
qiangzai
2022/09/16
4480
异步解决方案补充
揭秘ES6的迭代器
迭代器是ES2015中新增的规范,与之相关的for...of也是ES2015新增的。
挥刀北上
2021/12/15
4730
揭秘ES6的迭代器
ES6读书笔记(三)
前段时间整理了ES6的读书笔记:《ES6读书笔记(一)》,《ES6读书笔记(二)》,现在为第三篇,本篇内容包括:
全栈程序员站长
2021/07/06
1.2K0
字节前端高频手写面试题(持续更新中)1
观察者需要放到被观察者中,被观察者的状态变化需要通知观察者 我变化了 内部也是基于发布订阅模式,收集观察者,状态变化后要主动通知观察者
helloworld1024
2023/01/03
7790
从理解到实现轻松掌握 ES6 中的迭代器
JavaScript 中除了 Array 之外,ES6 还新增加了 Map、Set 结构,当我们需要操作这些数据时,就需要一种统一的接口来处理这些不同的数据结构。ES6 中新增加的 Iterator(迭代器)就提供了这样一种机制。
五月君
2020/11/19
5550
从理解到实现轻松掌握 ES6 中的迭代器
ES的新特性
首先来看一下ES6新增加的特性块级作用域,至于作用域的深入讲解后续会专门出一篇文章进行讲解
用户3045442
2020/08/06
1.2K0
当async/await遇上forEach
这是在做格式化wang.oa.com的时候遇到的一个问题,在邮件中提出后,收到了avenwu和erasermeng两位前辈的回复和指导,特此感谢。本文在他们指导后,经我整理后完成。
IMWeb前端团队
2019/12/03
2.1K0
【ES6+】005-ES6新特性:Symbol、迭代器、生成器
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型;
訾博ZiBo
2025/01/06
1060
【ES6+】005-ES6新特性:Symbol、迭代器、生成器
迭代器(Iterator)和生成器(Generator)-学习
上面的iterator就是一个最简单的迭代器,但是我们知道迭代器是帮助我们遍历某个数据结构的,所以这个迭代器看起来是没什么用的。
玖柒的小窝
2021/12/08
3620
「建议收藏」送你一份精心总结的3万字ES6实用指南(上)
写本篇文章目的是为了夯实基础,基于阮一峰老师的著作 ECMAScript 6 入门 以及 tc39-finished-proposals 这两个知识线路总结提炼出来的重点和要点,涉及到从 ES2015 到 ES2021 的几乎所有知识,基本上都是按照一个知识点配上一段代码的形式来展示,所以篇幅较长,也正是因为篇幅过长,所以就没把 Stage 2 和 Stage 3 阶段的提案写到这里,后续 ES2021 更新了我再同步更新。
用户4456933
2021/06/01
9070
「建议收藏」送你一份精心总结的3万字ES6实用指南(上)
好好学习JS异步原理
平常在工作中,我们经常与异步打交道,无论是函数节流、防抖,异步请求,都是异步操作。那么我们会经常使用setTimeout,Promise,Async/Await这三个东西。那么我们是真的了解这些api和语法糖他们的原理以及知识吗?本篇文章将从尽可能的说明白个中的原理和知识。
LamHo
2022/09/26
1.4K0
好好学习JS异步原理
相关推荐
Iterator与Generator
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验