Iterator 和 for...of 循环
Iterator 和 for...of 循环
Iterator(遍历器)意义
为Array、Object、Map、Set四种数据集合,提供统一的接口机制来处理所有不同的数据结构 。
任何数据结构,只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结 构的所有成员) 。
接口
//遍历器接口 interface Iterable{ [Symbol.iterator]():Iterator, } //指针对象 interface Iterator{ next(value?:any):IterationResult, } //返回结果 interface IterationResult{ value:any, done:boolean }
生成器
Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同 的是 ,
调用 Generator 函数后,该函数并不执行 , 返回的也不是函数运行结果 , 而是一个指 向内 部状态
的指针对象, 也就是上一章介绍的遍历器对象 Iterator Object ) 。
调用 Generator 函数返回一个遍历器对象,代表 Generator 函数的内部指针 。 以
后,每次调用遍历器对象的 next 方法,就会返回 一个有着 value 和 done 两个属性的对象 。
value 属性表示当前的内部状态的值,是 yield 语句后面那个表达式的值 : done 属性是一个
布尔值,表示是否遍历结束
作用
- 为各种数据结构提供一个统一 的、简便的访问接口;
- 使得 数据结构的成员能够按某种次序排列;
- ES6 创造了 一种新的遍历命令一for . . . of 循环, Iterator 接口 主要供 for ... of 消费。
过程
- 创建一个指针对象,指向当前数据结构的起始位置 。 也就是说,遍历器对象本质上就是 一个指针对象 。
- 第一次调用指针对象的 next 方法,可以将指针指向数据结构的第 一个成员 。
- 第二次调用指针对象的 next 方法,指针就指向数据结构的第二个成员 。
- 不断调用指针对象的 next 方法,直到它指向数据结构的结束位置 。
原理
每次调用 next 方法都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含 value 和 done 两个属性的对象。其中, value 属性是当前成员的值, done 属性是一个布尔值
与其他遍历语法的比较
以数组为例, JavaScript 提供了多种遍历语法。最原始的写法就是 for 循环 。
//麻烦 for (var index = 0; index < myArray.length ; index++) { console.log(myArray[index]); } // 不能跳出 myArray.forEach(function (value) { console.log(value) ; }) //被设计用来遍历对象,而不是数组 for(let i in myArray){ console.log(i) } //简洁,可跳出,统一接口 for(let i of myArray){ console.log(i) } //for ... of的等价写法 let iterator = myArray[Symbol.iterator](); let item = iterator.next(); while(!item.done){ console.log(item.value); item = iterator.next(); }
这种写法比较麻烦,因此数组提供了内置的 forEach 方法。
这种写法的问题在于,无法中途跳出 forEach 循环, break 命令或 return 命令都不能 奏效
for ... in循环可以遍历数组的键名。
for ... in 循环有几个缺点。
- 数组的键名是数字,但是 for ... in 循环是以字符串作为键名,“0”、“ 1 ”、" 2 ”等。
- for ... in 循环不仅可以遍历数字键名,还会遍历手动添加的其他键,甚至包括原 型链上的键。
- 某些情况下, for ... in 循环会以任意顺序遍历键名
总之, for . .. in 循环主要是为遍历对象而设计的,不适用于遍历数组。
for ... of 循环相比上面几种做法有一些显著的优点。
- 有着同 for ... in 一样的简洁语法,但是没有 for ... in 那些缺点。
- 不同于 forEach 方法 , 它可以与 break 、 continue 和 return 配合使用 。
- 提供了遍历所有数据结构的统一操作接口。