Iterator(迭代器)

2020-12-23  本文已影响0人  抽疯的稻草绳

概念

JavaScript原有的表示集合的数据结构有数组(Array)和对象(Object),ES6又添加了Map和Set。这样就有了4种数据集合,此时便需要一种统一的接口机制来处理不同的数据结构。

Iterator对象

1.Iterator就是这样一个统一的接口。任何数据结构,主要部署Iterator接口,就可以完成遍历。
2.Iterator接口主要供for...of使用(ES6创造的新的遍历命令)
3.Iterator对象本质上是一个指针对象。(创建时指向数据结构头部,依次调用next()方法后指针会移动,依次指向第1,2,3...个成员,最后指向结束位置)

next()方法
next()方法每次调用输出数据结构的成员。是一个包含value和done两个属性的对象。
形如:{value:当前成员的值,done:true/false} done代表是否循环结束

let color = ['red','yellow','blue']
let iterator = createIterator(colors);//createIterator如下自定义
iterator.next();//{value:'red',done:false}
iterator.next();//{value:'yellow',done:false}
iterator.next();//{value:'blue',done:false}
iterator.next();//{value:undefined,done:true}
//模拟实现createIterator:返回一个遍历器对象。
function createIterator(arr){
   var index = 0;
   return {
       next(){
       return index < arr.length ? { value:arr[index++],done:false} : { value:undefined,done:true}
      }
  }
}

默认迭代器

当使用for...of循环时,该循环会自动寻找Iterator接口。
ES6规定,一个数据结构只要具有Symbol.iterator属性,就是可遍历的。

const obj = {//obj具有Symbol.iterator(它是一个方法),因此是可遍历的
  [Symbol.iterator]:function(){
       return {
           next:function(){
               return {
                   value:1,
                   done:true
              }
          }
      }
  }
}

ES6的有些数据结构(数组)原生部署了Symbol.iterator属性(称为部署了遍历器接口),即不用任何处理就可以被for...of循环。另外一些数据结构(对象)没有。
以下数据结构原生部署Iterator接口:也就是说这些都可以使用for...of。除了这些,其他数据结构(如对象)的Iterator接口需要自己在Symbol.iterator属性上面部署,才会被for...of遍历。

//数组的默认迭代器:
let color = ['red','yellow','blue']
let arrIt = color[Symbol.iterator]();//返回一个迭代器
arrIt.next()//{value:'red',done:false}
//类数组arguments的默认迭代器:
function fn(){
   let argsIt = arguments[Symbol.iterator]();
   argsIt.next()
}
//类数组dom节点的默认迭代器:
let myP = document.getElementsByTagName('li');
let pIt = myP[Symbol.iterator]();
pIt.next();
//字符串的默认迭代器:
let str = 'dhakjda';
let strIt = str[Symbol.iterator]();
strIt.next();
//对象没有默认(即内置)迭代器:obj[Symbol.iterator] is not a function

Iterator使用场景
1.for of

//迭代器使用场景
//1.for of 循环:底层调用的是iterator.自动调用next().大部分使用迭代器都是使用它
//好处:1.语义化好 2.可以break
//for...of与其他遍历语法比较:
//1)for循环缺陷:1.不易理解 2.i,j变量不好管理容易混乱
//2)forEach缺陷:不能跳出循环,break/return均无效
//3)for in.1.不易理解 2.会循环出不是当前索引的值:另外添加的属性(自身的或者原型上的) xx.name=yy 总之:为对象设计的,不适合遍历数组
//4)for of优点:1.和for in一样简洁 2.可以跳出循环 3.提供统一操作接口

let colors = ['red','yellow','blue']
for(let color of colors){//数组
if(color == 'yellow')break;
   console.log(color);
}
function fn(){
   //let argsIt = arguments[Symbol.iterator]();
   //argsIt.next()
   for(let item of arguments){//arguments
       console.log(item)
  }
}
for(let item of myP){//dom节点
   console.log(item)
}

2.数组新增方法
//keys:返回index

//keys:返回index
let colors = ['red','yellow','blue']
for(let item of colors.keys()){//colors.keys()返回一个迭代器
   console.log(item)//0,1,2
}
//entries:返回包含value,index的数组
for(let [index,color] of colors.entries()){//colors.entries()返回一个迭代器
   console.log(index,color)//0 'red' 1 'yellow' 2 'blue'
}

3.数组的解构赋值

//对数组和Set结构解构赋值时,本质上也是调用Symbol.iterator()。
[index,color] = [0,'red']

4....扩展运算符

//扩展运算符也会调用默认的Iterator接口:转化为数组
let colors = ['red','yellow','blue']
let colors2 = ['black',...colors];//本质上也是使用迭代器
上一篇下一篇

猜你喜欢

热点阅读