for...of... 做爲遍歷全部數據結構的統一方式數組
for遍歷普通數組數據結構
for in 遍歷鍵值對dom
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); //foo bar }
配合結構使用測試
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 }
for..of循環時一種數據統一遍歷的方式this
for...of... Object TypeError 爲何?spa
Es可以表示有結構的數據類型愈來愈多 array obj set map 組合形式code
Iterable怎麼理解,就是一種接口(規格標準),例如任意一種數據類型都有toString方法,由於他們實現了統一的規格標準(實現了統一的接口)
可迭代接口就是一種 能夠被for..of..循環遍歷訪問的規格標準
換句話說,若是他實現了可迭代接口,他就能被for of循環遍歷
什麼是可迭代
console.log([]) console.log(new Set()) console.log(new Map())
咱們發現能夠被for -- of遍歷的對象都有
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可迭代接口須要知足
//對象實現一個iterable接口,對數組進行for..of const _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); }
生成器函數以前講過
上面也使用生成器實現了iterable接口
案例:添加一個發號器
//發號器 function * creatId(){ let id=1 while(true){ yield id++ } } const g = creatId() g.next() g.next() g.next()