Iterator可迭代接口

for..of.. for...of... 作为遍历所有数据结构的统一方式
for遍历普通数组
for in 遍历键值对
forEach 数组的遍历方法

const arr = [100,200,300,400]for(const item of arr){ console.log(item); //拿到的是每一个元素,而不是对应的下标 if(item>300){ break; } }//取代forEach方法,for..of..可以使用关键词break随时终止,forEach无法终止遍历 arr.forEach(function(item,index){})

其他的遍历
//伪数组的遍历(arguments) // dom操作时一些元素节点的列表 的遍历 //Set ,Map对象 const s = new Set(['foo',"bar"]) for(var i of s) { console.log(i); //foobar }

配合结构使用
const m = new Map() m.set({a:1},"value") m.set(true,100) for(var mm of m){ console.log(mm); //[ { a: 1 }, 'value' ][ true, 100 ] }//通过解构优化上面的for..of for(var [key,value] of m){ console.log(key,value); //{ a: 1 } value||true 100 }

注意,遍历对象会报错
//遍历对象会报错 const ddd = {naz:"mcgee",baz:100} for(var item of ddd){ console.log(item); //TypeError: ddd is not iterable }

Iterable 可迭代接口 for..of循环时一种数据统一遍历的方式
【Iterator可迭代接口】for...of... Object TypeError 为什么?
Es能够表示有结构的数据类型越来越多 array obj set map 组合形式
Iterable怎么理解,就是一种接口(规格标准),例如任意一种数据类型都有toString方法,因为他们实现了统一的规格标准(实现了统一的接口)
可迭代接口就是一种 可以被for..of..循环遍历访问的规格标准
换句话说,如果他实现了可迭代接口,他就能被for of循环遍历
什么是可迭代
  • 控制台测试 帮助->切换开发人员工具 查看输出结果
console.log([]) console.log(new Set()) console.log(new Map())


我们发现可以被for -- of遍历的对象都有
  • proto -> Symbol(Symbol.iterator):f values()
  • iterator接口约定对象内部必须要挂载一个叫iterator的方法,这个方法返回一个带有next()方法的对象
  • 不断调用next,就可以实现对内部的遍历
const result = ["foo","bar","baz"] const iterator = result[Symbol.iterator]()console.log(iterator.next()) //{value: "foo", done: false} console.log(iterator.next()) //{value: "bar", done: false} console.log(iterator.next()) //{value: "baz", done: false} console.log(iterator.next()) //{value: undefined, done: true}

const s = new Set([1,2,"as","foo"]) const it2 = s[Symbol.iterator]() console.log(it2.next()) console.log(it2.next()) console.log(it2.next()) console.log(it2.next()) console.log(it2.next())

自定义一个iterable可迭代的接口
实现iterable可迭代接口需要满足
  1. 有[Symbol.iterator] 方法
  2. [Symbol.iterator] 方法返回一个对象,这个对象实现了迭代器接口 Iterator
  3. 返回的对象具有一个next 方法,
  4. next方法返回一个 IterationResult 迭代结果的对象
  5. 对象有两个参数 value是每次的值,done表示是否完成迭代
//对象实现一个iterable接口,对数组进行for..ofconst _iterable = [1,23,4]const ob = { [Symbol.iterator](){ let index=0//计数器,用于判断是否迭代完成 return { next:function(){ return { value:_iterable[index], done:index++>=_iterable.length } } } } }for(var item of ob){ console.log(item) }

由于generator生成器也实现了iterator接口,因此上面方法可以进行改写
const ob = { * [Symbol.iterator](){//简写:[Symbol.iterator]:function * (){} for(let item of _iterable) { yield item } } }for(var item of ob){ console.log(item) //1,23,4 }

案例
//我想获取一个文件下的数据 const obj = { work:["吃饭","睡觉","打豆豆"], learn:["and","fuck","your"], gos:["mother"],//通过回调方式 cb(callback){ const result = [].concat(this.work,this.learn,this.gos) for(var item of result){ callback(item) } },//实现iterator接口,外部通过for..of..方式 [Symbol.iterator]:function (){ const arr = [...this.work,...this.learn,this.gos] let index=0; return { next:function(){ return { value:arr[index], done:index++>=arr.length } } } } }

傻瓜方式...
//耦合度太高,如果obj更改,则我还要加个方法 for(const item of obj.work) { console.log(item); } for(const item of obj.learn) { console.log(item); }

传统回调方式
//传统做法注册个回调 obj.cb(function(item){ console.log(item); })

for..of方式
//用可实现迭代接口 for(var item of obj){ console.log(item); }

Generator 生成器函数之前讲过
上面也使用生成器实现了iterable接口
案例:添加一个发号器
//发号器 function * creatId(){ let id=1 while(true){ yield id++ } } const g = creatId() g.next() g.next() g.next()

    推荐阅读