1. 迭代器
迭代器( lterator )是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口.就可以完成遍历操作。
- 1)ES6创造了一种新的遍历命令 for...of 循环 , Iterator 接口主要供 for...of 消费
- 2)原生具备 iterator 接口的数据 (可用for...of 遍历)
- Array
- Arguments
- Set
- Map
- String
- TypedArray
- NodeList
一种数据结构只要部署了 Iterator 接口,我们就称这种数据结构是“可遍历的”(iterable)。
ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”
let arr = [1,2,3,4,5,6];
for(let value of arr) {
console.log(value);
}
// 输出 1,2,3,4,5,6
-
3)迭代器工作原理
a) 创建一个指针对象,指向当前数据结构的起始位置
b) 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
c) 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
d) 每调用 next 方法返回一个包含 value 和 done 属性的对象
<font color="red" size=2>注: 需要自定义遍历数据的时候,要想到迭代器。 </font>
let arr = [1,2,3];
let iterator = arr[Symbol.iterator]();
// done 为true表示数组已经遍历完了
console.log(iterator.next()); //{value: 1, done: false}
console.log(iterator.next()); //{value: 2, done: false}
console.log(iterator.next()); //{value: 3, done: false}
console.log(iterator.next()); //{value: undefined, done: true}
-
4)迭代器应用 —— 自定义遍历
<font color="red" size=2>没有 Symbol.iterator属性 , 不能使用迭代器</font>
let obj = {
name: '天气',
weather: [
'晴天',
'多云',
'小雨',
'大雨',
'雾天'
]
}
// 需求使用 for...of 遍历obj,输出结果是weather里面的值
for(let value of obj) {
console.log(value); //Uncaught TypeError: obj is not iterable
}
给 obj 对象添加 Symbol.iterator属性
let obj = {
name: '天气',
weather: [
'晴天',
'多云',
'小雨',
'大雨',
'雾天'
],
[Symbol.iterator]() {
let index = 0; // 定义索引值
let self = this; // 保存this指向
return {
next() {
if (index < self.weather.length) {
const result = { value: self.weather[index], done: false };
index++;
return result;
}
return { value: undefined, done: true};
}
}
}
}
// 需求使用 for...of 遍历obj,输出结果是weather里面的值
for(let value of obj) {
console.log(value); // 晴天 多云 小雨 大雨 雾天
}
2. 生成器函数
执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。
形式上,Generator 函数是一个普通函数,但是有两个特征。
* 一是,function关键字与函数名之间有一个星号
* 二是,函数体内部使用yield表达式,定义不同的内部状态
- 1)声明与调用
<font color="1ba784">生成器函数传入参数与普通函数无异</font>
function * gen(){
yield 'hello';
yield 'world';
return 'ending';
}
let iterator = gen();
console.log(iterator.next()); //{value: "hello", done: false}
console.log(iterator.next()); //{value: "world", done: false}
console.log(iterator.next()); //{value: "ending", done: true}
console.log(iterator.next()); //{value: undefined, done: true}
- 2)生成器函数实例
<font color="1ba784">next方法可以传入参数,在生成器函数中获取,一个yield对应一个next传入的参数</font>
// 模拟获取 用户数据 订单数据 商品数据
function getUsers() {
setTimeout(()=>{
let data = '用户数据';
iterator.next(data);
},1000)
}
function getOrders() {
setTimeout(()=>{
let data = '订单数据';
iterator.next(data);
},1000)
}
function getGoods() {
setTimeout(()=>{
let data = '商品数据';
iterator.next(data);
},1000)
}
function * gen(){
let users = yield getUsers();
console.log(users);
let orders = yield getOrders();
console.log(orders);
let goods = yield getGoods();
console.log(goods);
}
let iterator = gen();
iterator.next();
- 3)生成器函数可以解决回调地狱,同时进行异步编程