ES6 中 for of 和迭代器 学习笔记
相比 ES3 到 ES5,ES5 到 ES6 是更重大的升级,既有大量语法糖,如 Arrow Function
、Template string
等等,更有模块化、class
、generator
等等强大的新特性。相信 ES6 会极大的改变我们编写 JS 的方式,而且 ES6(ES2015)已经在2015年6月17日发布,所以说可以开始学习 ES6 了。
本文是我学习ES6的笔记,大部分是概念摘要,代码演示等等,以弄清概念为要。
另,学习资料来源(会及时更新):es6-in-depth
ES5中,forEach
可以用来遍历数组元素,但它的缺陷是不能使用break
语句中断循环,也不能使用return
语句返回到外层函数。
强大的 for-of 循环
for (let value of [1, 2, 3]) { console.log(value); //输出 1 2 3 }
- 最简洁、最直接的遍历数组元素的语法
- 这个方法避开了 for-in 循环的所有缺陷
- 与
forEach()
不同的是,它可以正确响应break
、continue
和return
语句
其它集合也支持for-of循环
for-of 循环不仅支持数组,还支持大多数类数组对象,例如 DOM 的 NodeList
对象。它也支持字符串:
for (let chr of "abc12") { console.log(chr); // 输出 "a" "b" "c" "1" "2" }
另外还支持Map
和Set
对象的遍历。
深入理解
正如其它语言中的for/foreach语句一样,for-of循环语句通过方法调用来遍历各种集合。数组、Map、Set以及我们讨论的其它对象有一个共同点,它们都有一个迭代器方法。
任何对象都可以有/添加迭代器方法。
就像为对象添加myObject.toString()
方法,JS知道怎么把这个对象转化为字符串;你为对象添加迭代器方法myObject[Symbol.iterator]()
,JS也就知道了如何遍历这个对象。
[Symbol.iterator]
语法看起来很怪。Symbol
是ES6引入的新类型,标准定义了全新的symbol(如 Symbol.iterator
),来保证不与任何已有代码产生冲突。
任何有迭代器方法[Symbol.iterator]()
的对象都是可迭代的。
迭代器对象
迭代器方法 [Symbol.iterator]()
返回一个迭代器对象。迭代器对象可以是任何有 next()
方法的对象。for-of 循环将重复调用这个方法。
最简单的迭代器对象:
var zeroesForeverIterator = { [Symbol.iterator]: function() { return this; }, next: function() { return { done: false, value: 0 }; } };
每一次调用 next()
方法,它都返回相同的结果,告诉 for-of 循环:(a) 我们尚未完成迭代;(b)下一个值为0。这意味着 for (value of zeroesForeverIterator) {}
是一个无限循环。当然,一般来说迭代器不会如此简单。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
对数组来讲,请用
yield * array
,比如:@skyujilong generator也是iterator,你可以用
for of
代替forEach
。具体可以看开头部分。生成器如何配合 类似这种forEach 函数?
generator(生成器)
生成器是ES6最具魔力的特性。为什么这么说?对初学者来说,它与JS已有的特性截然不同,可能第一眼会觉得晦涩难懂。但是,从某种意义上来说,它使语言内部的常规行为变得更加强大。如果这都不是魔力,我不知道还有什么是。
注意:生成器可以简化代码,解决回调地狱。
生成器简介
什么是生成器?从一个示例开始:
它看起来有点像函数,对吗?它叫生成器函数(generator-function),和函数在很多方面一致。但有两处不同:
function
<->function*
yield
是关键词,语法和return
相似。区别在,函数(包括生成器函数)只能return
一次,生成器函数可以yield
任意次数。yield
表达式挂起生成器的执行,所以后面可以恢复。好,这就是很大的不同:常规函数不能暂停自己,但生成器函数可以。
生成器做了什么
当你调用
quips()
生成器函数时发生了什么?普通函数,当你调用它们时,它们立即运行,直到遇到return或抛出异常时才退出执行。
调用生成器函数看起来类似:
quips("jorendorff")
。但当你调用生成器函数时,它并没有开始运行。相反,它返回一个生成器(Generator)对象(上面的iter
)。你可以将这个生成器对象视为一次函数调用,只不过立即冻结了,它恰好在生成器函数的最顶端(第一行代码之前)冻结了。每次你调用生成器对象的
.next()
方法时,函数调用将其自身解冻并一直运行到下一个yield表达式前,再次暂停。调用最后一个
iter.next()
时,我们最终抵达生成器函数的末尾,所以返回结果中done
的值为true
。抵达函数的末尾就像returnundefined
,所以返回结果中value
的值为undefined
。用专业术语来说,每当生成器执行yields语句,生成器的堆栈帧(stack frame,含有本地变量、参数、临时值、生成器内部当前的执行位置)被移出堆栈。但是,生成器对象保留了对这个帧的引用(或复制),所以稍后调用
.next()
可以重新激活帧并且继续执行。注意:生成器不是线程。
生成器可以暂停,恢复运行。那么问题来了,这有什么用?
生成器是迭代器
结合上一部分的迭代器,我们来构造一个
range
迭代器,就简单地从一个数增加到另一个数。上面的实现看起来像Java或Swift,不坏,但也不简洁。看起来迭代器很好用,但实现起来有点麻烦。
有更好的方式吗?用生成器:
4行代替23行,之所以可行,因为生成器就是迭代器(generators are iterators)。所有的生成器都内置
.next()
和[Symbol.iterator]()
的实现。你只要写循环行为。如何使用生成器作为迭代器的能力?
可以变成: