for...of循环的使用

更新日期: 2021-06-24阅读: 1.1k标签: 循环
or…of语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。
– MDN

基本使用

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

// 遍历数组
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遍历一下对象:

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]就可以了,比如:

let object = {
a: 1,
b: 2,
c: 3,
[Symbol.iterator]: function() {}
}

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

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
}

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

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循环中,也可以用在数组的解构上:

let arr = [...loop10]; // arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]


可迭代对象与generator函数

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

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函数可以简化上述步骤:

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上

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方法,这里实现了吗?没错,这里还真实现了!你可以试试:

let itarator = loop10Gen();
itarator[Symbol.iterator]() === itarator; // 返回true

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


for…of与for…in的区别

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

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

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'
}

for…in会遍历对象原型和原型链上的可枚举的属性。

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()方法来判断:

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:

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调用了~~'
}
}
原文来自:https://kai666666.com/2021/06/24/for-of循环的使用/


链接: https://www.fly63.com/article/detial/10461

跳出 forEach

使用for...in遍历对象时,会遍历原型链上的可枚举属性,这可能会导致一些意想不到的问题。所以你一定收到过这样的建议,使用数组的forEach来代替for...in循环。本文给大家总结了5种在forEach中跳出循环的变通之法

JavaScript循环下的async/await

在进行业务开发的过程中,使用了数组的高级函数map,同时使用了ES6语法async/await,发现在map循环下任务是异步执行的,并不符合预期。Array的循环方法map、forEach、filter、reduce、some、every等是并行迭代,可以理解为async/await的效果是无效的

如何中断forEach循环

在使用for循环的时候可以使用break 或者return语句来结束for循环(return直接结束函数),但是如果使用forEach循环如何跳出循环呢?首先尝试一使用return语句----木有效果

用于JavaScript中的循环和同时循环

如果您需要重复大量的代码数百次,这会变得非常笨拙。而且,它也不是很有用。例如,如果希望它重复X次呢?这就是循环的用武之地。次数通常由变量决定,但也可以由实际数字决定。

Js中循环执行

循环:就是一遍又一遍执行相同或者相似的代码,循环的两个要素:循环体:重复执行的代码;循环条件:控制循环的次数

为啥要放弃for循环?

创建一个新的数组,新的数组中的元素是通过检查指定数组中符合条件的元素;注意:1. filter()不会对空数组进行检测;2. filter()不会改变源是数组;

解决使用Vue-Router出现无限循环问题

我在项目里面用到了的是全局守卫,beforeEach,方便管理 不过遇到了一个问题,就是在beforeEach()中设置好判断条件后出现了无限循环的问题 当时的代码如下:

Node.js事件循环

对于本文中一些知识点任然有些模糊,懵懵懂懂,一直都在学习中,通过学习事件循环也看了一些文献,在其中看到了这一句话:除了你的代码,一切都是同步的,我觉得很有道理,对于理解事件循环很有帮助。

关于for循环中使用setTimeout的四种解决方案

我们先来简单了解一下setTimeout延时器的运行机制。setTimeout会先将回调函数放到等待队列中,等待区域内其他主程序执行完毕后,按时间顺序先进先出执行回调函数。本质上是作用域的问题

Js循环的几种方法

for 常用于循环数组 ,for in 常用来循环对象,不建议循环数组,因为i是字符串 可能会有隐患问题,for in 循环会找到 prototype 上去,所以最好在循环体内加一个判断

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!