迭代器就是实现了next方法的对象,并且next方法需要满足以下要求
1)传入一个或没有参数的函数
2)返回一个对象,对象里包含value和done两个key,当迭代完的时候done返回是true,否则是false,当迭代完毕的时候value值可以省略也可以是其他默认值
let foo={
next(){
return {value:1,done:true}
}
}
console.log(foo.next());
可迭代对象就是对象里实现了[Symbol.iterator]方法,方法里面需要返回一个包含next方法的对象,next方法的要求和迭代器里面的next一样,可迭代对象的特点就是我们可以对其进行for of方法,但是不能map,因为map是Array类上的方法
let foo={
[Symbol.iterator]:function(){
let a=0
return {
next(){
if(a<2){
a=a+1
return {value:a,done:false}
}
return {value:a,done:true}
}
}
}
}
// 当我们把对象变成可迭代对象后 我们就可以进行of循环
// 返回的值就是next return出来的value值 循环次数就是return出来done为false的次数
for(let i of foo){
console.log(i);//1 2
}
// 报错
foo.map((item)=>{
console.log(item);
})
原生可迭代对象有String,Array,解构数组,map,set,arguements和获取的dom集合,weakSet和weakMap不属于原生可迭代对象
注意:解构对象不是迭代器
可迭代对象里面可以添加return方法,当我们对这个对象进行for of的时候如果因为break、continue、return、throw中断了循环操作,就会调用return方法,let iterator=foo[Symbol.iterator]()这种调用方式如果return方法调用再调用next依旧会按照之前的继续迭代
let foo={
[Symbol.iterator]:function(){
let a=0
return {
next(){
if(a<5){
a=a+1
return {value:a,done:false}
}
return {value:a,done:true}
},
return(){
console.log('结束');
return {value:a,done:true}
}
}
}
}
for(let item of foo){
console.log(item);//1 2 结束
if(item=='2')break
}
let iterator=foo[Symbol.iterator]()
console.log(iterator.next());//{ value: 1, done: false }
console.log(iterator.return());//{ value: 1, done: true }
console.log(iterator.next());//{ value: 2, done: false }
1)定义:生成器就是函数就是一个命名带*,用yield控制执行,返回值是一个空对象,原型是一个可迭代对象,可迭代对象里面有next,return方法,所以我们可以调用next等方法
function* foo(){
yield 1
}
console.log(foo);//[GeneratorFunction: foo]
console.log(foo());//Object [Generator] {}
2)返回值:返回值的value的值就是yield里面的值,每次调用一次next,就会执行到yield,如果所有的yield都执行完了,value的值就是undefined,done就是false,如果还有下一次yield,则done是true
function* foo(){
yield 1
yield 2
}
let foo1=foo()
console.log(foo1.next());//{ value: 1, done: false }
console.log(foo1.next());//{ value: 2, done: false }
console.log(foo1.next());//{ value: undefined, done: true }
console.log(foo1.next());//{ value: undefined, done: true }
3)参数
function *foo(num){
let n=yield num*2
let m=yield n*10
yield m*4
}
let foo1=foo(1)//这个传入的参数是里面的num
console.log(foo1.next(3));//这个传入的参数是没有地方接收的,因为是第一次yield,没有上一次yield { value: 2, done: false }
console.log(foo1.next(1.5));//这个传入的参数是里面的n { value: 15, done: false }
console.log(foo1.next(100));//这个传入的参数是里面的m { value: 400, done: false }
1)生成器的终止,注意调用return的时候返回值是return里传入的值
function *foo(num){
yield 1
yield 2
yield 3
}
let foo1=foo()
console.log(foo1.next());//{ value: 1, done: false }
console.log(foo1.return(1.5));//{ value: 1.5, done: true }
console.log(foo1.next());//{ value: undefined, done: true }
2)生成器的throw:调用throw如果有try catch就会到catch里面,执行至下一个yield 然后返回结果
function *foo(num){
try {
yield 1
yield 2
yield 3
} catch (error) {
yield 4
}
yield 5
yield 6
}
let foo1=foo()
console.log(foo1.next());//{ value: 1, done: false }
console.log(foo1.throw(1.5));//{ value: 1.5, done: true }
console.log(foo1.next());//{ value: undefined, done: true }
因为生成器函数返回 的就是一个原型对象是生成器的对象,所以直接写一个生成器函数就可以替代迭代器了
// 生成器替代迭代器
let obj={
arr:[1,2,3],
*[Symbol.iterator](){
yield* this.arr
}
}
for(let item of obj){
console.log(item);//1 2 3
}
// 语法糖 yield*后面需要跟上一个可迭代对象 返回可迭代对象的key
let arr=[1,3]
function *bar() {
yield* arr
}
let bar1=bar()
console.log(bar1.next());
// { value: 0, done: false }
// { value: 1, done: false }
class Person{
arr=[1,2,3];
// *加在[Symbol.iterator]前面 在生成器里面[Symbol.iterator]函数执行会
// 返回一个可迭代对象,这样写也是返回一个可迭代对象,所以是等同的
*[Symbol.iterator](){
yield* this.arr
}
}
// 创建可迭代对象 通过new
let per=new Person()
// 由下可知用了生成器创建的可迭代对象也是可以用for of进行循环的
for(let item of per){
console.log(item);//1 2 3
}
// 模拟异步函数
// 为什么要把promise放到函数里面,因为模拟需要多次调用
// 为什么要用promise 而不是直接setTimeout 为了得到上一次的结果
function foo(params) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(params);
}, 2000);
});
}
// 模拟多个异步函数
function* bar(num) {
let result = yield foo(num);
let result1 = yield foo(result);
yield foo(result1);
}
let bar1 = bar(1);
//多个异步函数变成同步的实现
// 方案一
function foo2(params) {
params.next().value.then((res)=>{
console.log(res);//1
params.next(2).value.then((res)=>{
console.log(res);//2
params.next(3).value.then((res)=>{
console.log(res);//3
})
})
})
}
// 方案二 自执行函数
function foo1(params) {
function exe(res) {
// 获得的是一个promise
let data = params.next(res);
if (!data.done) {
data.value.then((res) => {
console.log(res); //1 1 1
exe(res);
});
} else {
return;
}
}
exe();
}
// 调用
foo1(bar1);
foo2(bar1);
1.async:在函数前面可以加async关键词,代表该函数是一个异步函数,异步函数得返回值如果是一个promise,返回值由promise决定,如果是一个有then方法得函数,则由then决定,异步函数调用后得返回值是一个promise
2.await:只能在async里面使用 加了后需要等await后的执行完才能执行下面的代码并且下面的代码会被放入微任务
如果await后面是一个普通的值,那么会直接返回这个值;