ES6 - 迭代器
迭代器简介
迭代器是一个对象,它允许我们一次访问一个对象集合。
以下内置类型默认为可迭代 −
- String
- Array
- Map
- Set
如果对象实现了一个函数,其键为 [Symbol.iterator] 并返回一个迭代器,则该对象被视为 可迭代。for...of 循环可用于迭代集合。
示例
以下示例声明一个数组,使用 for..of 循环对其进行标记和迭代。
<script>
let marks = [10,20,30]
//使用 for..of 检查可迭代性
for(let m of marks){
console.log(m);
}
</script>
上述代码的输出将如下所示 −
10 20 30
示例
以下示例声明一个数组,标记并检索迭代器对象。[Symbol.iterator]() 可用于检索迭代器对象。迭代器的 next() 方法返回一个具有 'value' 和 'done' 属性的对象。'done' 是布尔值,在读取集合中的所有项目后返回 true。
<script> let marks = [10,20,30] let iter = marks[Symbol.iterator](); console.log(iter.next()) console.log(iter.next()) console.log(iter.next()) console.log(iter.next()) </script>
上述代码的输出将如下所示 −
{value: 10, done: false}
{value: 20, done: false}
{value: 30, done: false}
{value: undefined, done: true}
自定义可迭代
JavaScript 中的某些类型是可迭代的(例如数组、Map 等),而其他类型则不是(例如类)。默认情况下不可迭代的 JavaScript 类型可以使用可迭代协议进行迭代。
以下示例定义了一个名为 CustomerList 的类,该类将多个客户对象存储为一个数组。每个客户对象都有 firstName 和 lastName 属性。
要使此类可迭代,该类必须实现 [Symbol.iterator]() 函数。此函数返回一个迭代器对象。迭代器对象有一个函数 next,它返回一个对象 {value:'customer',done:true/false>。
<script>
//用户定义的迭代
class CustomerList {
constructor(customers){
//将客户对象添加到数组中
this.customers = [].concat(customers)
}
//实现迭代器函数
[Symbol.iterator](){
let count=0;
let customers = this.customers
return {
next:function(){
//从数组中检索客户对象
let customerVal = customers[count];
count+=1;
if(count<=customers.length){
return {
value:customerVal,
done:false
}
}
//如果所有客户对象都已迭代,则返回 true
return {done:true}
}
}
}
}
//创建客户对象
let c1={
firstName:'Sachin',
lastName:'Tendulkar'
}
let c2={
firstName:'Rahul',
lastName:'Dravid'
}
//定义一个客户数组并初始化它 let customers=[c1,c2]
//将客户传递给类的构造函数
let customersObj = new CustomerList(customers);
//使用 for..of 进行迭代
for(let c of customersObj){
console.log(c)
}
//使用 next() 方法进行迭代
let iter = customersObj[Symbol.iterator]();
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
</script>
上述代码的输出将如下所示 −
{firstName: "Sachin", lastName: "Tendulkar"}
{firstName: "Rahul", lastName: "Dravid"}
{
done: false
value: {
firstName: "Sachin",
lastName: "Tendulkar"
}
}
{
done: false
value: {
firstName: "Rahul",
lastName: "Dravid"
}
}
{done: true}
生成器
在 ES6 之前,JavaScript 中的函数遵循运行至完成模型。ES6 引入了称为生成器的函数,该函数可以在中途停止,然后从停止的地方继续。
生成器在函数名称前加上星号 * 字符,并包含一个或多个 yield 语句。yield 关键字返回一个迭代器对象。
语法
function * generator_name() {
yield value1
...
yield valueN
}
示例
该示例定义了一个生成器函数 getMarks,其中包含三个yield语句。与普通函数不同,生成器函数 getMarks()在调用时不会执行该函数,而是返回一个迭代器对象,该对象可帮助您执行生成器函数内的代码。
第一次调用 markIter.next() 时,开头的操作将运行,yield 语句将暂停生成器的执行。后续调用 markIter.next() 将恢复生成器函数,直到下一个 yield 表达式。
<script>
//定义生成器函数
function * getMarks(){
console.log("步骤 1")
Yield 10
console.log("步骤 2")
Yield 20
console.log("步骤 3")
Yield 30
console.log("函数结束")
}
//返回迭代器对象
let markIter = getMarks()
//调用语句直到第一个 Yield
console.log(markIter.next())
//在最后一个 Yield 之后恢复执行直到第二个 Yield 表达式
console.log(markIter.next())
//在最后一个 Yield 之后恢复执行直到第三个 Yield 表达式
console.log(markIter.next())
console.log(markIter.next()) // 迭代完成;未返回任何值
</script>
上述代码输出将概要 −
步骤 1
{value: 10, done: false}
步骤 2
{value: 20, done: false}
步骤 3
{value: 30, done: false}
函数结束
{value: undefined, done: true}
示例
以下示例通过
* evenNumberGenerator 生成器函数创建一个无限偶数序列。
我们可以使用 next() 或使用 for of 循环遍历所有偶数,如下所示
<script>
function * evenNumberGenerator(){
let num = 0;
while(true){
num+=2
yield num
}
}
// 显示前两个元素
let iter = evenNumberGenerator();
console.log(iter.next())
console.log(iter.next())
//使用 for of 迭代到 12
for(let n of evenNumberGenerator()){
if(n==12)break;
console.log(n);
}
</script>
上述代码的输出将如下所示 −
{value: 2, done: false}
{value: 4, done: false}
2
4
6
8
10

