ES6(5):迭代器、生成器
程序员文章站
2022-07-13 08:42:12
...
文章目录
一、迭代器
迭代器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提
供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
1. ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费
2. 原生具备 iterator 接口的数据(可用 for of 遍历)
- Array
- Arguments
- Set
- Map
- String
- TypedArray
- NodeList
3. 工作原理
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
- 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
- 每调用 next 方法返回一个包含 value 和 done 属性的对象
- 注: 需要自定义遍历数据的时候,要想到迭代器。
4. 示例:
//声明一个数组
const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
//使用 for...of 遍历数组
for(let v of xiyou){
console.log(v);
}
//使用迭代器
let iterator = xiyou[Symbol.iterator]();
//调用对象的next方法
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
5. 自定义遍历数据 示例:
//声明一个对象
const banji = {
name: "终极一班",
stus: [
'xiaoming',
'xiaoning',
'xiaotian',
'knight'
],
[Symbol.iterator]() {
//索引变量
let index = 0;
//保存this
let _this = this;
return {
next: function () {
if (index < _this.stus.length) {
const result = { value: _this.stus[index], done: false };
//下标自增
index++;
//返回结果
return result;
}else{
return {value: undefined, done: true};
}
}
};
}
}
//遍历这个对象
for (let v of banji) {
console.log(v);
}
二、生成器
生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。
1. 特殊在:
- 字面量(函数声明 / 函数表达式)的关键字 function 后面多了一个 * ,* 前后允许有空白字符。 * 的位置没有限制
function * gen(){
}
function *gen(){
}
function* gen(){
}
- 函数体中多了 yield 运算符,yield 相当于函数的暂停标记,也可以认为是函数的分隔符
function * gen(){
yield 'a';
yield 'b';
yield 'c';
}
2. 基本用法
function * gen(){
console.log(111);
yield 'a';
console.log(222);
yield 'b';
console.log(333);
yield 'c';
console.log(444);
}
let iterator = gen();
iterator.next();
iterator.next();
iterator.next();
iterator.next();
function * gen(){
console.log(111);
yield 'a';
console.log(222);
yield 'b';
console.log(333);
yield 'c';
console.log(444);
}
let iterator = gen();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
- 在调用 gen() 时,函数体中的逻辑并不会执行(控制台没有输出)
- 生成器函数返回的结果是迭代器对象,调用迭代器对象的 next 方法可以得到
yield 语句后的值 - 第一次调用 iterator.next(),函数开始执行,直到遇到第一个 yield 表达式为止
- 第二次调用 iterator.next(),函数从上次 yield 表达式停下的地方,一直执行到下一个 yield 表达式以此类推,一直执行到函数结束 (如果有return语句,就执行到return 语句)
- 第n次调用 iterator.next(),函数已经运行完毕,next方法返回对象的value属性为undefined,done属性为true
3. 生成器函数参数
function * gen(arg){
console.log(arg);
let one = yield 111;
console.log(one);
let two = yield 222;
console.log(two);
let three = yield 333;
console.log(three);
}
//执行获取迭代器对象
let iterator = gen('AAA');
console.log(iterator.next());
//next方法可以传入实参
console.log(iterator.next('BBB'));
console.log(iterator.next('CCC'));
console.log(iterator.next('DDD'));
第二次调 iterator.next() 方法传入的实参,将作为第一个 yield 语句的返回结果。以此类推。
4. 生成器函数实例
实例1:1s 后控制台输出 111 2s后输出 222 3s后输出 333
// 回调地狱
setTimeout(() => {
console.log(111);
setTimeout(() => {
console.log(222);
setTimeout(() => {
console.log(333);
}, 3000);
}, 2000);
}, 1000);
用迭代器的写法:
function one(){
setTimeout(()=>{
console.log(111);
iterator.next();
},1000)
}
function two(){
setTimeout(()=>{
console.log(222);
iterator.next();
},2000)
}
function three(){
setTimeout(()=>{
console.log(333);
iterator.next();
},3000)
}
function * gen(){
yield one();
yield two();
yield three();
}
//调用生成器函数
let iterator = gen();
iterator.next();
实例2:模拟获取 用户数据 订单数据 商品数据
//模拟获取 用户数据 订单数据 商品数据
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();