迭代器
- 迭代器
(Iterator)
是一种接口((Iterator)
接口就是数据类型中的Sysmbol.iterator
的属性,如下图),为各种不同的数据结构提供统一的访问机制。
-
ES6创造一种新的遍历命令
for...of
循环,Iterator
接口主要供for...of
消费,简单的说就是只要该数据类型部署了Iterator
接口,就可以使用for...of
进行遍历。 -
具备
Iterator
接口的数据类型(即可用于for...of
遍历)- Array
- Arguments
- Set
- Map
- String
- TypedArray
- NodeList
-
使用for…of遍历数组 (如果不清楚for…of与for…in的区别,可以看看我之前写的博客:比较JavaScript中for、forEach、for…in、for…of的区别https://blog.csdn.net/weixin_45660621/article/details/121258086?spm=1001.2014.3001.5501)
var arr = ["江流", "心猿", "木龙", "刀圭", "意马"];
//使用for...of遍历数组
for (let value of arr) {
console.log(value);
}
工作原理
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的
next
方法,指针自动指向数据结构的第一个成员 - 接下来不断调用
next
方法,指针一直往后移动,直到指向最后一个成员 - 每调用
next
方法返回一个包含value
和done
属性的对象
注:需要自定义遍历数据的时候,要想到迭代器
var arr = ["江流", "心猿", "木龙", "刀圭", "意马"];
//查看next方法
let iterator = arr[Symbol.iterator]();
console.log(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: '意马', done: false}
console.log((iterator.next()));//越界
迭代器的应用-自定义遍历数据
- 需求: 通过
for...of
遍历一个对象中指定的数组元素,且只返回数组元素。
const xiyou = {
name: "西游记",
member: [
"江流",
"心猿",
"木龙",
"刀圭",
"意马"
],
[Symbol.iterator]() {
// 索引变量
let index = 0;
//
return {
next: () => {
if (index < this.member.length) {
const result = { value: this.member[index], done: false };
// 下标自增
index++;
// 返回结果
return result;
}
else {
return { value: undefined, done: true };
}
}
}
}
}
for(let value of xiyou)
{
console.log(value);
}
生成器
- 生成器函数是ES6提供的一种异步编程解决方案
- 每次也是通过
Iterator.next()
方法调用 - 可以通过
for...of
进行遍历 yield
是函数代码分割符
function * gen(){
yield "江流";
yield "心猿";
yield "意马";
}
// next指针方法访问
let iteratot = gen();
console.log(iteratot.next());//{ value: '江流', done: false }
console.log(iteratot.next());//{ value: '心猿', done: false }
console.log(iteratot.next());//{ value: '意马', done: false }
console.log(iteratot.next());//越界
// for...of遍历
for(let value of gen())
{
console.log(value);
}
生成器函数参数
- 该函数可以像正常函数一样传入形参
next
方法可以传入实参,实参会作为整个yield 语句
的返回值- 第二次调用
next
方法会作为第一次整个yield 语句
的返回值 - 第三次调用
next
方法会作为第二次整个yield 语句
的返回值 - 以此类推
function * gen(arg){
console.log(arg);//正常打印形参
let one = yield "江流";
console.log(one);//1
let tow = yield "心猿";
console.log(tow);//2
let three = yield "意马";
console.log(three);//3
}
// next指针方法访问
let iteratot = gen(0);//传入形参
console.log(iteratot.next());//
console.log(iteratot.next(1));//作为第一个yield语句的返回值
console.log(iteratot.next(2));//作为第二个yield语句的返回值
console.log(iteratot.next(3));//作为第三个yield语句的返回值
生成器函数实例
- 第一个需求: 1s 后控制台输出 111 2s后输出 222 3s后输出333
ES5中使用定时器套回调函数的方法的写法:
setTimeout(() => {
console.log((111));
setTimeout(() => {
console.log(222);
setTimeout(() => {
console.log(333);
}, 3000);
}, 2000)
}, 1000);
如果有很多的回调函数,就会不断在回调函数内部叠加,形成回调地狱
ES6使用生成器函数的写法:
function one() {
setTimeout(() => {
console.log(111);
iterator.next();
}, 1000);
}
function two() {
setTimeout(() => {
console.log(111);
iterator.next();
}, 2000);
}
function three() {
setTimeout(() => {
console.log(111);
iterator.next();
}, 3000);
}
function* gen() {
yield one();
yield two();
yield three();
}
// 调用生成器函数
let iterator = gen();
iterator.next();
**第二个需求:**模拟异步获取 用户数据 订单数据 商品数据
function getUsers(){
setTimeout(() => {
let data = "用户数据";
// 调用next方法,并将数据传入
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();