迭代器和可迭代对象
迭代器
认识什么叫迭代器
维基百科对迭代器的定义:迭代器是确使用户在容器对象上遍访的对象,使用该接口无需关心对象内部实现的细节,维基百科的解释确实很正确,但是他喜欢用概念解释概念,所以说也不好理解。我觉得用大白话来形容:就是迭代器可以帮助我们对某个数据结构进行遍历的对象,在很多语言都有,比如说java、python…
JavaScript中迭代器
- 在JavaScript中迭代器也是一个具体的对象,不过这个对象需要符合迭代器协议(iterator protocol)。迭代器协议定义了一系列的值产生的标准。
如果我们阅读英文文档会发现这个位置其实中文翻译的是有问题的,下面这副图才是正确解释
let arr = [1,2,3,4,5]//符合迭代器协议的对象,可以通过某个标准拿到arr数组中的一个又一个的项,在js中这个标准就是一个特定的next方法
- next方法也不是随便定义的一个方法,他也有一定的要求
- 他是一个无参数或者一个参数的函数,返回一个应当拥有以下两个属性的对象(done、value)
- 当done的值为false的时候,就代表迭代器可继续产出值,当迭代完毕之后就返回一个true(迭代结束的时候true可以省略)
- value就是返回false之后需要给使用者返回的值,是最直观的提现,使用者可以拿到这个值进行一系列的操作,当迭代完毕的时候done的值为true,value的值是可选的,如果它存在那么就作为迭代器结束之后的默认值返回。 ```javascript const arr = [1, 2, 3, 4, 5]; let index = 0; const iterableArr = { next() { if (index < arr.length) { return { done: false, value: arr[index++] }; } else { return { done: true, value: undefined }; } }, }; console.log(iterableArr.next()); //{ done: false, value: 1 } console.log(iterableArr.next()); //{ done: false, value: 2 } console.log(iterableArr.next()); //{ done: false, value: 3 } console.log(iterableArr.next()); //{ done: false, value: 4 } console.log(iterableArr.next()); //{ done: false, value: 5 } console.log(iterableArr.next()); //{ done: true, value: undefined } console.log(iterableArr.next()); //{ done: true, value: undefined }
//这样我们就实现了一个简易的迭代器
<a name="ef03596e"></a>### 可迭代对象<a name="5ad4034e"></a>#### 认识什么叫可迭代对象可迭代对象和迭代器完全是两个概念,不能混淆了,可迭代对象需要实现(adorably protocol协议)并且返回一个迭代器。```javascriptconst iterableObj = {arr: [1, 2, 3, 4, 5],[Symbol.iterator]() {let index = 0;return {next: () => {if (index < this.arr.length) {return { done: false, value: this.arr[index++] };} else {return { done: true };}},};},};for (const item of iterableObj) {console.log(item); //1,2,3,4,5}
迭代器这种代码,通过调用next去获取数组的每一项,我们在开发中是很少写的,但是这种for..of的代码在开发中是很常见的,for..of可以看做这种语法的语法糖。
可迭代对象的应用
- 可以应用于for..of遍历
- 也可以引用到展开运算符中
- 如果是一个对象,那么也是可以的,那么就有一个问题,for..of遍历对象的时候是不可以的,会报错的,例子:
```javascript let obj = { name: “coderwei”, age: 19, };
- 如果是一个对象,那么也是可以的,那么就有一个问题,for..of遍历对象的时候是不可以的,会报错的,例子:
let newObj = { …obj }; console.log(newObj); //{name:’coderwei’,age:19} for (const item of Obj) { console.log(item); //报错 } //展开运算符用在一个对象上原理不是利用可迭代对象,这时ES9提出来的,对对象使用的时候会做特殊的处理,而且展开运算符只能将对象展开到另一个对象。如果展开到数组里依旧会报错:xxx is not iterable
3. 解构- 当我们使用解构赋值的时候,本质上也是利用可迭代对象的特性,当前同样要区分解构对象和数组```javascript//解构数组let arr = [1,2,3]const [x ,y ,z ] = arrconsole.log(x,y,z) //1,2,3const [x ,z ,y] = arrconsole.log(x,y,z) // 1,3,2//解构对象let obj = {name:'coderwei',age:19}const {name,age} = objconsole.log(name.age) //'coderwei',19const {obj,name} = objconsole.log(name.age) //'coderwei',19//我们可以发现当我们解构对象的时候,跟定义变量的顺序是无关的,而解构数组则是有关的,也证明了解构数组只是调用迭代器的next方法拿到一个个的value,然后将它赋值给定义的变量
封装一个创建迭代器的函数
function createIterator(arr){let index = 0return {next:function(){if(index<arr.length){return {done:false,value:arr[index++]}}else{return {done:true,value:undefined}}}}}let arr = [1, 2, 3, 4, 5];let itor = createIterator(arr);console.log(itor.next()); //{ done: false, value: 1 }console.log(itor.next()); //{ done: false, value: 2 }console.log(itor.next()); //{ done: false, value: 3 }console.log(itor.next()); //{ done: false, value: 4 }console.log(itor.next()); //{ done: false, value: 5 }console.log(itor.next()); //{ done: true, value: undefined }console.log(itor.next()); //{ done: true, value: undefined }
