-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ES6 系列之迭代器与 for of #90
Comments
var done = i >= item.length; |
在日常代码中 有什么情况是使用for of会比较方便吗 |
@zjp6049 只想要遍历值,而不需要用到 index 或 key 等的时候 const arr = ['a', 'b', 'c'];
for (let val of arr) {
console.log(val);
}
// "a"
// "b"
// "c" |
var done = i >= item.length; 大佬,上面这个是items,小bug |
@zjp6049 作者在开头已经提到了,
|
完整版createIterator function createIterator(items){
function addIterator(items){
let i = 0
let done = false
return {
next() {
done = i >= items.length
return {
value: items[i++],
done
}
}
}
}
let iterator = addIterator(items)
iterator[Symbol.iterator] = ()=> addIterator(items)
return iterator
} |
@ystarlongzi @cobish @zjp6049 我觉得 for...of 的主要运用的场景并不是作者文中开头提到的那些吧。比如你要遍历一个数组,不想使用 for 循环,数组提供的 map/forEach 等也都能完成对应的功能。for...of 只能搭配部署了 iterator 接口的值来进行使用。而不同值的遍历也有对应的遍历方法,比如要遍历对象,使用 for ... in 循环同样能完成对应的工作。 |
博主好文。这个跟 python 语言里面的 iterator 有什么区别 |
没有区别 |
babel编译中 例如当前 |
你认真的吗。。。。每次判断对_iteratorNormalCompletion的赋值 都会覆盖 “_iteratorNormalCompletion = true”,所以去掉是无所谓的。 |
深入JS讨论很多,到ES6这慢慢好像就少了。。。 |
大佬,迭代器那段代码 var done = i >= item.length; 应该是 items。 |
条件语句中是赋值,并不是判断相等与否~ |
所以forEach中return无效而for可以的原因是forEach迭代器没有return方法这个原因? |
起源
一段标准的 for 循环代码:
看着很简单,但是再回顾这段代码,实际上我们仅仅是需要数组中元素的值,但是却需要提前获取数组长度,声明索引变量等,尤其当多个循环嵌套的时候,更需要使用多个索引变量,代码的复杂度就会大大增加,比如我们使用双重循环进行去重:
为了消除这种复杂度以及减少循环中的错误(比如错误使用其他循环中的变量),ES6 提供了迭代器和 for of 循环共同解决这个问题。
迭代器
所谓迭代器,其实就是一个具有 next() 方法的对象,每次调用 next() 都会返回一个结果对象,该结果对象有两个属性,value 表示当前的值,done 表示遍历是否结束。
我们直接用 ES5 的语法创建一个迭代器:
for of
除了迭代器之外,我们还需要一个可以遍历迭代器对象的方式,ES6 提供了 for of 语句,我们直接用 for of 遍历一下我们上节生成的遍历器对象试试:
结果报错
TypeError: iterator is not iterable
,表明我们生成的 iterator 对象并不是 iterable(可遍历的)。那什么才是可遍历的呢?
其实一种数据结构只要部署了 Iterator 接口,我们就称这种数据结构是“可遍历的”(iterable)。
ES6 规定,默认的 Iterator 接口部署在数据结构的 Symbol.iterator 属性,或者说,一个数据结构只要具有 Symbol.iterator 属性,就可以认为是"可遍历的"(iterable)。
举个例子:
我们直接 for of 遍历一个对象,会报错,然而如果我们给该对象添加 Symbol.iterator 属性:
由此,我们也可以发现 for of 遍历的其实是对象的 Symbol.iterator 属性。
默认可遍历对象
然而如果我们直接遍历一个数组对象:
尽管我们没有手动添加 Symbol.iterator 属性,还是可以遍历成功,这是因为 ES6 默认部署了 Symbol.iterator 属性,当然我们也可以手动修改这个属性:
除了数组之外,还有一些数据结构默认部署了 Symbol.iterator 属性。
所以 for...of 循环可以使用的范围包括:
模拟实现 for of
其实模拟实现 for of 也比较简单,基本就是通过 Symbol.iterator 属性获取迭代器对象,然后使用 while 遍历一下:
内建迭代器
为了更好的访问对象中的内容,比如有的时候我们仅需要数组中的值,但有的时候不仅需要使用值还需要使用索引,ES6 为数组、Map、Set 集合内建了以下三种迭代器:
以数组为例:
Map 类型与数组类似,但是对于 Set 类型需要注意以下:
Set 类型的 keys() 和 values() 返回的是相同的迭代器,这也意味着在 Set 这种数据结构中键名与键值相同。
而且每个集合类型都有一个默认的迭代器,在 for-of 循环中,如果没有显式指定则使用默认的迭代器。数组和 Set 集合的默认迭代器是 values() 方法,Map 集合的默认迭代器是 entries() 方法。
这也就是为什么直接 for of 遍历 Set 和 Map 数据结构,会有不同的数据结构返回:
遍历 Map 数据结构的时候可以顺便结合解构赋值:
Babel 是如何编译 for of 的
我们可以在 Babel 的 Try it out 中查看编译的结果:
对于这样一段代码,编译的结果如下:
至少由编译的结果可以看出,使用
for of
循环的背后,还是会使用 Symbol.iterator 接口。而这段编译的代码稍微复杂的地方有两段,一段是 for 循环这里:
跟标准的 for 循环写法有些差别,我们看下 for 语句的语法:
initialize、test 和 increment 三个表达式之间用分号分割,它们分别负责
初始化操作
、循环条件判断
和计数器变量的更新
。for 语句其实就相当于:
代码的逻辑为:先进行初始化,然后每次循环执行之前会执行 test 表达式,并判断表达式的结果来决定是否执行循环体,如果 test 计算结果为真值,则执行循环体中的 statement。最后,执行 increment 表达式。
而且值得注意的是,其实 for 循环中的三个表达式中任意一个都可以被忽略,不过分号还是要写的。
比如
for(;;)
,不过这就是一个死循环……比如:
又比如:
然后我们再来看 Babel 编译的这个 for 循环表达式:
用 while 的写法相当于:
是不是就好懂了很多呢,然后你就会发现,其实
_iteratorNormalCompletion = true
这句是完全没有必要的……另外一段稍微复杂的代码是:
因为
_iteratorNormalCompletion = (_step = _iterator.next()).done
,所以 _iteratorNormalCompletion 表示的就是是否完成了一次完整的迭代过程,如果没有正常的迭代完成,并且迭代器有 return 方法时,就会执行该方法。而之所以这么做,就要提到迭代器的 return 方法。
引用阮一峰老师的 ECMAScript 6 入门:
我们可以举个例子:
不过正如你在编译后的代码中看到,仅仅是在有 return 函数的时候执行了 return 函数而已,return 函数中返回的值其实并不生效……
但是你不返回值或者返回一个基本类型的值的话,结果又会报错……
这是因为 return 方法必须返回一个对象,而这又是 Generator 规范决定的……
总之如果是在浏览器中使用的话,return 函数的返回值其实并不生效 T^T
ES6 系列
ES6 系列目录地址:https://github.com/mqyqingfeng/Blog
ES6 系列预计写二十篇左右,旨在加深 ES6 部分知识点的理解,重点讲解块级作用域、标签模板、箭头函数、Symbol、Set、Map 以及 Promise 的模拟实现、模块加载方案、异步处理等内容。
如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励。
The text was updated successfully, but these errors were encountered: