目录
一,迭代器
1.迭代器概念
2.迭代器的基本应用
3.迭代器原理
4.应用:自定义遍历数据
二,生成器
1.生成器概念
2.生成器的基本应用
3.yield表达式的值
4.应用:模拟获取数据
三,总结
迭代器(lterator)是一种接口,为各种不同的数据结构提供统一的访问机制。
任何数据结构只要部署lterator接口,就可以完成遍历操作。
//以下数据结构支持lterator接口
String
Array
Map
Set
TypedArray
函数中的arguments对象
NodeList对象
for/of循环,扩展操作符 可以直接操作可迭代对象
const xiyou = ['迭代器','生成器'];
for (let v of xiyou) {
console.log(v) // 迭代器,生成器
}
//注意:
// for/of v值保存的是键值
// for/in v值保存的是键名
data = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(Math.max(...data)); // 8
迭代器也可用于结构赋值
let arr = [ 10 , 18 , 20];
let [a , b , c] = arr;
console.log(c); // 20
首先要了解3个不同的类型
- 可迭代对象:类似于Array,Set,Map 都是可以迭代的。
- 迭代器对象:是指任何具备next()方法的,且方法返回迭代结果对象的对象,用于执行迭代。
- 迭代器结果对象:是指具有属性value和done的对象,用于保存每次迭代的结果。
要迭代一个可迭代对象,先调用迭代器方法获得一个迭代对象,然后重复调用迭代器对象的 next() 方法,直到返回迭代器结果对象 done 属性为 true;
可迭代对象的迭代器方法名为:[Symbol.iterator]
自定义遍历数据,要想起迭代器
const obj = {
name: 'yiban',
friend: [
'duan',
'zhou',
'zhang',
'wei'
],
[Symbol.iterator]() {
//索引变量
let index = 0;
//创建一个指针对象
return {
//创建next方法(必须)
next: () => { //这里箭头函数解决this指向问题
if (index < this.friend.length) {
const res = {
value: this.friend[index],
done: false
};
index++;
return res
} else {
return {
value: undefined,
done: true
}
}
}
}
}
}
for (let v of obj) {
console.log(v)
}
生成器(Generators)是一种强大的新的ES6语法定义的迭代器,是一种异步编程解决方案。
生成器就是一个特殊的函数。
当调用生成器next()方法时,生成器函数会一直运行达到第一个yield表达式的时候,当第二次运行的时候会停在第二个yield上。
//调用下面这个生成器函数不会运行下面的代码,而是会返回一个生成器对象
//调用该对象的next()方法才会运行
function* fn() {
console.log('第一次执行');
yield '分割线1'; //yield分割线调用一次只执行一次分割的位置
console.log('第二次执行');
yield '分割线2';
console.log('第三次执行');
yield '分割线3';
console.log('第四次执行');
}
//调用生成器函数,得到一个生成器
let han = fn();
console.log(han.next()); //第一次执行 {value: '分割线1', done: false}
console.log(han.next()); //第二次执行 {value: '分割线2', done: false}
console.log(han.next()); //第三次执行 {value: '分割线3', done: false}
console.log(han.next()); //第四次执行 {value: undefined, done: true}
生成器通过yield向调用者返回值,调用者通过next()方法给生成器传值。
在调用生成器的next()方法时,运行到第一个yield表达式,yield关键字后面的表达式会被求值,该值成为next()调用的返回值,这时生成器函数在求值yield表达式途中停,下一次调用next()方法时,传入的参数会变成暂停的yield表达式的值 。
function* fn(str) {
console.log(str); // 传参
let a = yield 1; //a == 'b'
console.log(a); // b
let b = yield 2; //b == 'c'
console.log(b); // c
let c = yield 3; //c == 'd'
console.log(c); // d
return 100
}
//执行获取迭代器对象
let han = fn('传参');
//han.next()方法可以传入实参
console.log(han.next('a')); //第一次调用;参数将被丢弃,生成器回送1
//执行传入的参数返回值为第一个yiele整体返回结果
console.log(han.next('b')); //参数是b,生成器回送2
console.log(han.next('c')); //参数是c,生成器回送3
console.log(han.next('d')); //参数是d,生成器回送100
模拟获取 用户数据 订单数据 商品数据
1秒后打印用户数据,1秒后打印订单数据,1秒后打印商品数据
function fa() {
setTimeout(() => {
let yon = '用户数据';
//传入参数并调用
han.next(yon);
}, 1000);
}
function fb() {
setTimeout(() => {
let din = '订单数据';
han.next(din);
}, 1000);
}
function fc() {
setTimeout(() => {
let shang = '商品数据';
han.next(shang);
}, 1000);
}
function* fn() {
let a = yield fa();
console.log(a); //1s 用户数据
let b = yield fb();
console.log(b); //2s 订单数据
let c = yield fc();
console.log(c); //3s 商品数据
}
let han = fn();
//调用
han.next();
生成器是一种强大的通用控制结构,可以使用生成器在单线程js代码中创建某种协作线程系统。尽管这些函数是异步的,但代码看起来还是顺序的同步的。
利用生成器来做异步操作会造成代码难以解释,ES6+新增了async/await 和 promise 提供了异步编程解决方案 。