You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Object.prototype[Symbol.iterator]=function(){letproperties=Object.keys(this)letcount=0letisdone=falseletnext=()=>{letvalue=this[properties[count]]if(count==properties.length){isdone=true}count++return{done: isdone, value }}return{ next }}
理解 JavaScript 中的循环
在
JavaScript
的世界中,我们可以使用很多种循环表达式:while
表达式do...while
表达式for
表达式for...in
表达式for...of
表达式所有这些表达式都有一个基本的功能:它们会重复一件事情直到一个具体的条件出现。
在这篇文章中,我们将深入
for...of
表达式,去了解它是如何工作的,以及在我们的应用中可以使用它来优化代码的地方。for…of
for...of
是一种for
表达式,用来迭代iterables(iterable objects)
直到终止条件出现。下面是一个基础的例子:
使用比
for
循环更好的代码,我们遍历了arr
数组。你知道如果我们使用
for
循环,我们将必须使用数学和逻辑去判断何时我们将会达到myname
的末尾并且停止循环。但是正如你所见的,使用for...of
循环之后,我们将会避免这些烦人的事情。for...of
有以下通用的使用方法:variable
- 保存每次迭代过程中的迭代对象的属性值iterable
- 我们进行迭代的对象Iterables(可迭代的对象) and Iterator(迭代器)
在
for...of
循环的定义中,我们说它是“迭代 iterables(iterable objects)”。这个定义告诉我们for...of
循环只能用于可迭代对象。那么, 什么是可迭代的对象(
iterables
)?简单来说的话,可迭代对象(Iterables)是可以用于迭代的对象。在
ES6
中增加了几个特性。这些特性包含了新的协议,其中就有迭代器(Iterator)协议和可迭代(Iterable)协议。参考
MDN
的描述,“可迭代协议允许JS
对象定义或者修改它们的迭代行为,比如哪些值可以被for...of
循环到。”同时“为了变成可迭代的,对象必须实现@@iterator
方法,这意味着这个对象(或者其原型链上的对象)必须包含一个可以使用Symbol.iterator
常量访问的@@iterator
的属性”说人话就是,对于可以使用
for...of
循环的对象来说,它必须是可迭代的,换句话就是它必须有@@iterator
属性。这就是可迭代协议。所以当对象有
@@iterator
属性的时候就可以被for...of
循环迭代,@@iterator
方法被for...of
调用,并且返回一个迭代器。同时,迭代器协议定义了一种对象中的值如何返回的方式。一个迭代器对象必须实现
next
方法,next 方法需要遵循以下准则:举个例子:
基本上,
@@iterator
方法回返回一个迭代器,for...of
循环正是使用这个迭代器去循环操作目标对象从而得到值。因此,如果一个对象没有@@iterator
方法同时这个返回值是一个迭代器,for...of
循环将不会生效。内置的可迭代对象有有以下这些:
注意,Object 不是可迭代的。如果我们尝试使用
for...of
去迭代对象的属性:将会抛出一个异常:
我们可以用下面的方式检查一个对象是否可迭代:
看到了吧,打印的结果是
function
, 这意味着@@iterator
属性存在,并且是函数类型。如果我们在 Object 上面进行尝试:哇!
undefined
表示不存在。for…of: Array
数组是可迭代对象。
这是我们可以对它使用
for...of
循环的原因。for…of: String
字符串也是可迭代的。
for…of: Map类型
for…of: Set类型
for…of: TypedArray类型
for…of: arguments对象
arguments对象是可遍历的吗?我们先来看:
答案出来了。如果进一步探讨,arguments其实是IArguments类型的对象,而且实现了IArguments接口的class都有一个@@iterator属性,使得arguments对象可遍历。
for…of: 自定义可遍历对象(Iterables)
正如上一节那样,我们可以创建一个自定义的可以通过
for..of
遍历的可遍历对象。这里创建了一个可遍历的
obj
对象,通过[Symbol.iterator]
赋予它一个@@iterator
属性,然后创建一个返回遍历器的方法。记住,遍历器一定要有一个
next()
方法。在next方法里面,我们实现了在for...of遍历过程中会返回的值,这个过程很清晰。
Let’s test this our
obj
against a for..of to see what will happen:耶!成功了!
把Object和普通对象(plain objects)变成可遍历
简单对象是不可遍历的,通过
Object
得到的对象也是不可遍历的。我们可以通过自定义遍历器把@@iterator添加到Object.prototype来实现这个目标。
properties
变量里面包含了通过调用Object.keys()
得到的object的所有属性。在next方法里面,我们只需要返回properties里面的每一个值,并且通过更新作为索引的count变量来获取下一个值。当count达到properties的长度的时候,就把done设为true,遍历就结束了。用Object来测试一下:
成功了!!!
用简单对象来测试一下:
也成功了!! :)
所以我们可以把这个添加到polyfill里面,然后就可以在app里面使用for...of来遍历对象了。
在ES6的类(class)中使用for…of
我们可以用for...of来遍历class的实例中的数据列表。
Profiles类有一个
profile
属性,包含一个用户列表。当我们需要在app中用for...of来展示这个列表的时候,如果这样做:显然是不行的。
为了把
profiles
变成可遍历,请记住以下规则:@@iterator
属性。@@iterator
的方法一定要返回一个遍历器(iterator).iterator
一定要实现next()
方法。我们通过一个熟悉的常量
[Symbol.iterator]
来定义这个@@iterator然后,如果我们这样运行:
我们可以显示 profiles 的属性
Async Iterator
ECMAScript 2018 引入了一个新的语法,可以循环遍历一个 Promise 数组,它就是
for-await-of
和新的 SymbolSymbol.asyncIterator
。iterable 中的
Symbol.asyncIterator
函数需要返回一个返回 Promise 的迭代器。[Symbol.iterator]
和[Symbol.asyncIterator]
的区别在于前者返回的是{ value, done }
而后者返回的是一个Promise
,只不过当 Promise resolve 的时候传入了{ value, done }
。我们上面的那个 f 例子将如下所示:
这个
f
是可异步迭代的,你看它总是返回一个 Promise ,而只有在迭代时 Promise 的 resolve 才返回真正的值。要遍历
f
,我们不能使用for..of
而是要使用新的for-await-of
,它看起来会是这样:我们也可以使用
for-await-of
来循环遍历一个 Promise 数组:Conclusion
在这篇文章中我们深入研究了
for...of
循环,我们首先定义理解什么是for...of
,然后看看什么是可迭代的。for...of
为我们节省了许多复杂性和逻辑,并有助于使我们的代码看起来很清晰易读,如果你还没有尝试过,我认为现在正是时候。The text was updated successfully, but these errors were encountered: