迭代器
Iterator是一种接口,任何数据结构只要部署了Iterator接口,就可以完成遍历操作。
是对象的一种属性:Symbol.iterator,这个属性是个函数。Symbol(Symbol.iterator)
const arr=[1,2,3,4];
let iterator=arr[Symbol.iterator]();//arr[Symbol.iterator]表示调用arr对象的属性//Symbol.iterator,其是个函数,所以括号表示调用,函数调用返回一个对象。
console.log(iterator.next());
手动实现迭代器:
function myIterator(arr){
let index=0;
return {next(){
if(index<arr.length){
return {value:arr[index++],done:false}
}
else{
return {value:undefined,done:true}
}
}
}
}
arr=[1,2,3,4];
let iterator=myIterator(arr);
console.log(iterator.next());
array、string等都部署了迭代器接口,但是对象没有,所以要自定义迭代器接口:
//自定义迭代器接口让对象可以实现for...of...循环
var obj={
a:1,
b:2,
c:3,
[Symbol.iterator](){
let index=0;
//因为obj没有length属性,所以用Map映射obj(因为Map有size方法)
let m=new Map([['a',1],['b',2],['c',3]]);//初始化时传一个数组进去,数组里是键值对
return {next(){
let mEntriesArray=[...m.entries()];
if(index<m.size){
return {value:mEntriesArray[index++],done:false}
}
else{
return {value:undefined,done:true}
}
}
}
}
}
var iter=obj[Symbol.iterator]();
console.log(iter.next());
//此时obj也可用for...of迭代了
for(let i of obj){
console.log(i);
}
迭代和遍历的区别?
迭代:从目标源依次逐个抽取的方式来提取数据,目标源一定是有序的(有索引)并且连续的。如Array、String、Map、Set、arguments、NodeList都可以用for…of…迭代。对象里的数据就不是有序的。
生成器
什么是生成器?生成器是一个带星号的函数(function*),而且可以暂停执行和恢复执行(函数里面的代码不是一次执行完的)。
生成器具体使用方式:
- 在生成器函数内部执行一段代码,如果遇到 yield 关键字,那么 JavaScript引擎将返回yield关键字后面的内容给外部(父协程),并暂停该函数的执行。
- 外部函数可以通过 next 方法恢复函数(gen协程)的执行
js引擎V8如何实现一个函数的暂停和恢复执行?
需要先来了解一下协程:协程是一种比线程更加轻量级的存在。你可以把协程看成是跑在线程上的任务,一个线程上可以存在多个协程,但是在线程上同时只能执行一个协程,比如当前执行的是 A 协程,要启动 B 协程,那么 A 协程就需要将主线程的控制权交给 B 协程,这就体现在 A 协程暂停执行,B 协程恢复执行;同样,也可以从 B 协程中启动 A 协程。通常,如果从 A 协程启动 B 协程,我们就把 A 协程称为 B 协程的父协程。协程不像线程一样被操作系统内核管理,而是由程序控制,所以协程切换性能更高,没那么消耗资源(线程切换需要消耗CPU)。生成器就是协程的一种实现方式。
协程的四点规则:通过调用生成器函数 genDemo 来创建一个协程 gen,创建之后,gen 协程并没有立即执行;要让 gen 协程执行,需要通过调用 gen.next;当协程正在执行的时候,可以通过 yield 关键字来暂停 gen 协程的执行,并返回主要信息给父协程;如果协程在执行期间,遇到了 return 关键字,那么 JavaScript 引擎会结束当前协程,并将 return 后面的内容返回给父协程。
我们把执行生成器的代码封装成一个函数,并把这个执行生成器代码的函数称为执行器。
生成器返回一个迭代器对象。
迭代器可以通过生成器的方式来生成:
function* test(){
console.log(1);
yield 5;
console.log(2);//在调用第二个next()之前不打印
let value=yield 2;
console.log(value);
yield 3;
yield 4;
}
var iter=test();
console.log(iter.next(‘one’));//调用next()方法才会执行test函数。执行一次yield一下,下面代码中止
console.log(iter.next(‘two’));
console.log(iter.next());
console.log(iter.next());
//for(let i of iter){
// console.log(i);
//}
//用生成器手动实现迭代器接口
var obj={
a:1,
b:2,
c:3,
[Symbol.iterator]:function*(){
let index=0;
//因为obj没有length属性,所以用Map映射obj(因为Map有size方法)
let m=new Map([['a',1],['b',2],['c',3]]);//初始化时传一个数组进去,数组里是键值对
let mEntriesArray=[...m.entries()];
while(index<mEntries.length){
yield mEntriesArray[index++];
}
}
}
for(let i of obj){
console.log(i);
}