Iterator 和 for...of 循环
Iterator(遍历器)的概念
Iterator(遍历器)概念: 它是一种接口,为各种不同的数据结构提供统一的访问机制,即for...of循环,该循环会自动去寻找 Iterator 接口。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
Iterator 的作用:
-提供一个统一的、简便的访问接口; -使得数据结构的成员能够按某种次序排列; -ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。
原生具备Iterator接口的数据(可用for...of遍历的)
1、Array
2、arguments
3、Set
4、Map
5、String
6、typeArray
7、NoeList
ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator
属性。(换句话说,所谓Iterator接口,其实在相当于是一个对象的属性。这个属性的名字叫Symbol.iterator)
Symbol.iterator
属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。
来看一个简单例子
// 声明一个数组 var fruits = ['苹果', '香蕉', '西红柿', '榴莲']; for (let k of fruits) { console.log(k); } // 苹果 // 香蕉 // 西红柿 // 榴莲 console.log(fruits); // 打印这个数组,数组中就有这个接口(Symbol.Iterator属性):Symbol(Symbol.iterator): ƒ values()
Iterator工作原理:
-创建一个指针对象,指向当前数据结构的起始位置; -第一次调用对象的next方法,指针自动指向数据结构的第一个成员; -接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员; -每调用next方法返回一个包含value和done属性的对象
注:需要自定义遍历数据的时候,要想到遍历器
下面的例子是数组的Symbol.iterator
属性。
// 声明一个数组 const fruits = ['苹果', '香蕉', '西红柿', '榴莲']; // 获取数组的iterator对象 let iterator = fruits[Symbol.iterator](); // 调用对象的next方法 console.log(iterator.next()); // {value: "苹果", done: false} console.log(iterator.next()); // {value: "香蕉", done: false} console.log(iterator.next()); // {value: "西红柿", done: false} console.log(iterator.next()); // {value: "榴莲", done: false} console.log(iterator.next()); // {value: undefined, done: true}
对象(Object)没有默认部署 Iterator 接口
const obj = { name: "终极一班", stu: ['唐僧', '孙悟空', '猪八戒', '沙和尚'] } // 采用for...of遍历这个对象 for (var k of obj) { console.log(k); } // obj is not iterable
一个对象如果要具备可被for...of
循环调用的 Iterator 接口,就必须在Symbol.iterator
的属性上部署遍历器生成方法(原型链上的对象具有该方法也可)。
Iterator(遍历器)的应用
部署在对象身上
let obj = { data: ['唐僧', '孙悟空', '猪八戒', '沙和尚'],
// 部署iterator接口 [Symbol.iterator]() { let index = 0; return { next: () => { if (index < this.data.length) { return { value: this.data[index++], done: false }; } return { value: undefined, done: true }; } }; } }; // 采用for...of遍历这个对象 for (let k of obj) { console.log(k); } // 唐僧 // 孙悟空 // 猪八戒 // 沙和尚
部署在原型上
class RangeIterator { constructor(start, stop) { this.value = start; this.stop = stop; } // 部署遍历器接口 [Symbol.iterator]() { return this; } next() { var value = this.value; if (value < this.stop) { this.value++; return { done: false, value: value }; } return { done: true, value: undefined }; } } var result = new RangeIterator(0, 3); for (var value of result) { console.log(value); // 0, 1, 2 }
for...of 循环
一个数据结构只要部署了Symbol.iterator
属性,就被视为具有 iterator 接口,就可以用for...of
循环遍历它的成员。也就是说,for...of
循环内部调用的是数据结构的Symbol.iterator
方法。
for...of
循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments
对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串。