ES6学习——迭代器(Iterators):return和throw概述

来源:互联网 发布:台湾驱动透视源码 编辑:程序博客网 时间:2024/04/30 07:00

Iterator接口还有两个可选方法,一直都没讲,主要是由于浏览器没有完全支持这两个方法。最后我们看一下:


然后规范上有一段描述:

NOTE 2 Typically callers of these methods should check for their existence before invoking them. Certain ECMAScript language features includingfor-of, yield*, and array destructuring call these methods after performing an existence check. Most ECMAScript library functions that accept Iterable objects as arguments also conditionally call them.


通过上面的描述可以看到,在一些情况下这两个方法会被执行。但JS内置的这些迭代器都没有实现这两个方法,在规范的7.4.6章节中定义了一个方法叫IteratorClose( iterator, completion ),描述了如何调用可选的return方法:

The abstract operation IteratorClose with arguments iterator and completion is used to notify an iterator that it should perform any actions it would normally perform when it has reached its completed state:
1. Assert: Type(iterator) is Object.
2. Assert: completion is a Completion Record.
3. Let return be GetMethod(iterator, "return").
4. ReturnIfAbrupt(return).
5. If return is undefined, return Completion(completion).
6. Let innerResult be Call(return, iterator, « »).
7. If completion.[[type]] is throw, return Completion(completion).
8. If innerResult.[[type]] is throw, return Completion(innerResult).
9. If Type(innerResult.[[value]]) is not Object, throw a TypeError exception.
10. Return Completion(completion).


我们可以在规范中搜索IteratorClose,看看什么情况下会调用:for-of/in循环结束,或者被break,continue,return,throw打断循环的时候,数组解构赋值的时候,Array.form,Set,Map,Promise.all,Promise.race用迭代器传入参数时。return可选方法的主要目的就是做一些资源清理的工作,当迭代完成的时候。由于浏览器基本不支持这个可选方法调用,我们用Kinoma Studio去测试:

function objectEntries(obj) {let index = 0;let propKeys = Object.getOwnPropertyNames(obj);return {[Symbol.iterator]() {return this;},next() {if (index < propKeys.length) {let key = propKeys[index];index++;return { done:false,value: [key, obj[key]] };} else {return { done: true };}},return(val){trace("entries are over\n");return {done:true,value:val}}};}let obj = { first: 'Jane', last: 'Doe' },iter = objectEntries(obj)[Symbol.iterator]();for(let entry of iter){trace(entry+"\n");//first,Janebreak;}//打印entries are overtrace("after return.....\n" + iter);//这里iter竟然设置成了undefinedfor(let entry of iter){//这里会报错trace(entry+"\n");}

KS的处理也比较有意思,虽然说确实会调用return,但是调用完成之后会把iter设置成undefined,难道就是为了让迭代器不能在迭代,目的符合规范的要求了,但做法比较奇怪。

下面这点更有意思:

let obj = { first: 'Jane', last: 'Doe' },iter = objectEntries(obj)[Symbol.iterator]();let [x] = iter;trace(x + "\n");for(let entry of iter){trace(entry+"\n");}/*entries are overfirst,Janelast,Doeentries are over*/
数组解构赋值完,会调用return方法,然后迭代器还可以继续迭代,最后又调用了一次return,比较无语。我没有在继续试其它的几种情况,有兴趣的自己去搞吧。


其实return方法可以手工调用的,就像手工调用next方法一样。这个机制还是挺有用的,就像try-catch-finally里的finally一样,给了一个做最后处理的机会。但是浏览器目前支持的情况都不好,所以我们有个印象就行了。

至于throw,在生成器(Generators)中会有用,我们留在讲生成器的时候再说吧。


*以上全部代码在Kinoma Studio中通过测试

0 0