Iterator
Iterator
为不同的数据结构提供统一的访问机制,只要它部署Iterator接口,就可以完成遍历操作。
它的流程其实是跟链表的遍历很相似的:创建一个指针对象,指向当前数据结构的起始位置,然后不断的next()
,每次返回的是一个对象数据,包含value和done两个字段供访问。
for...of
循环实际上会去自动找Iterator
接口。
ES6规定,默认的Iterator接口部署在数据结构的Symbol.iterator
这个key上,一个数据结构只要具有Symbol.iterator
方法,就可以认为是“可遍历的”。
再次提醒,千万注意:Symbol.iterator
里面的i是小写!!!
为啥要用Iterator
跟其他语言一样,提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。
原生支持Iterator的类型
原生的表述数据集的类型:Array
、Object
、Map
、Set
。
而实际上原生支持Iterator
的数据结构是:Array
、Map
、Set
。
Object
默认不支持,其实非要手写支持的话,还不如直接用Map
。
字符串也支持,因为它类似于Array
手动支持Iterator
Symbol.iterator
是一个函数,返回的是一个遍历器,执行next(),不断的返回包含value和done两个字段的对象数据。
类似于Array的Object
例如arguments
,对于这种,其实我们可以直接使用Array
的Iterator
接口:
|
|
如之前所述,能否支持遍历,仅是检查Symbol.iterator
这个key而已,所以普通的对象也能支持Iterator
,单还不如用Set
呢
普通对象部署Iterator
|
|
需要注意的是,Iterator
的作用是使得数据结构的成员能够按某种次序排列,所以偶尔蛋疼的这么设定,可能仅仅是为了定义一个复杂的访问顺序,但是使用的时候仅仅for...of
就好了。
因此也不能强说这么做是不对的。
不过,对于这种,用类不是更好一点么?例如:
|
|
注意这里的Symbol.iterator
的定义,能不能有更简便的方法呢:
|
|
再次强调,只是在定义某种次序的访问
,没规定要怎么访问!!只是在默认支持的数据结构中按顺序访问了而已。
Iterator的使用
一个经典的硬性使用Iterator的示例:
|
|
其实直接用for...of
更简便:
|
|
几个默认使用 Iterator 的场景
总结自 ECMAScript6 入门
- 解构赋值,例如
let [x,y] = set
- 扩展运算符,例如
['a', ...arr, 'd']
- yield,例如`yield [2,3,4];`
- 由于数组的遍历会调用遍历器接口,所以任何接受数组作为参数的场合都符合条件
- for…of
- Array.from()
- Map(), Set(), WeakMap(), WeakSet()(比如new Map([[‘a’,1],[‘b’,2]]))
- Promise.all()
- Promise.race()
Generator
简而言之,结合着上面的Iterator
,可以理解Generator
实际上是生成了一个可遍历的结果数据集,数据集的元素有哪些,由yield
和return
定义,函数执行的结果就是数据集的Iterator
。
例如:
|
|
那么不断执行ite.next()
并以!ite.next().done
为判断条件的执行结果为:1,2,3
。
next
可以传入值,作为执行时上一个yield
的执行返回结果:
需要注意的是,在执行next(true)时,counterGen 中那个注释掉的console语句中,i其实是6,后面置的0。
执行的最终结果中,value是0。
也就是说,yield的结果其实是可以被后面的语句给改掉的,或者可以将例子中while语句{}包起来的部分认为是一个函数,最后返回i是最终的结果。
也可以这么理解:执行到下一个yield
时,才返回了之前的结果,大概、或许是这样吧……
总结一小下:
- 定义时,function 后面跟着一个
*
- 内部用
yield
定义一个可被遍历到的元素(状态) return
也会被认为是一个可被遍历到的元素(状态),如果没有return
或没跟返回值,value会是undefined
。- 状态会被后面的同步代码所改变,直到下一次
yield
之前都可以
不得不说的 yield *
本来不想说这个,感觉要变成基础知识集了,不过研究中间件偏偏遇到了,不得不说……
yield*
最大的作用,就是将Generator
嵌在另一个Generator
的内部执行。
|
|
执行结果是13
,是的,2不会被输出,但是如果换成:
|
|
就等同于:
输出就是123
就好了。
而这也是koa2的中间件核心实现机制,笑话一下自己搞出来的遍历行为,然后傻在next
的调用上了,囧~~
可以查看
Generator更多的用法
建议查看 ECMAScript6 入门
Async
语法糖,是对Generator
的改进。
返回的结果是一个Promise
。
错误机制
只需注意几点就行了。
- 返回结果是
Promise
,所以按Promise
的错误处理就行了 async
内部的await
指定的状态,是同步
的,全都成功整体状态才会成功,任何一个失败了,整体也就失败了(后面的不执行了),除非用try…catch包起来或者用.catch处理一下
for await of
|
|