若是學過設計模式和java的人都知道iterator是什麼東西,在Symbol.iterator出現後,JS能夠定義本身的迭代器java
迭代器,它是用於訪問集合類的標準訪問方法,它能夠把訪問邏輯從不一樣類型集合中抽象出來,從而避免向外部暴露集合內部的結構。好比咱們訪問一個數組可能使用for循環或者map,foreach,filter等for(int i=0; i<array.size(); i++) { ... get(i) ... }
, 可是當咱們想要遍歷鏈表(linkedlist)的時候就得使用while循環while((e=e.next())!=null) { ... e.data() ... }
, 以上兩種方式咱們都必須知道集合的內部結構是怎麼樣的咱們纔可使用對應的循環方式去循環整個集合,那麼這樣就形成了很大的耦合度,當咱們把一個集合的類型從Arrarlist變成Linkedlist的時候,那麼原來客戶端的代碼必須重寫,由於咱們集合變了,遍歷的方式也必須改爲對應的方式。爲解決以上問題,Iterator模式老是用同一種邏輯來遍歷集合: for(Iterator it = c.iterater(); it.hasNext(); ) { ... }
,這樣就在必定程度上解決了以上的問題。設計模式
遍歷數組一般使用for循環,ES5的話也可使用forEach,ES5具備遍歷數組功能的還有map、filter、some、every、reduce、reduceRight等,只不過他們的返回結果不同。可是使用foreach遍歷數組的話,使用break不能中斷循環,使用return也不能返回到外層函數數組
var myArray=[1,2,4,5,6,7]
myArray.name="殺馬特"
Array.prototype.method=function(){
console.log(this.length);
}
for (var index in myArray) {
console.log(myArray[index]);
}
複製代碼
使用for in 也能夠遍歷數組,可是會存在如下問題:bash
那麼除了使用for循環,如何更簡單的正確的遍歷數組達到咱們的指望呢(即不遍歷method和name),ES6中的for of更勝一籌.函數
var myArray=[1,2,4,5,6,7]
myArray.name="殺馬特"
Array.prototype.method=function(){
console.log(this.length);
}
for (var index of myArray) { //這裏的index輸出的是value而不是索引
console.log(index);
}
複製代碼
注意:for-of目前js實現的對象有array,string,argument以及後面更高級的set,Map
當咱們遍歷對象的時候可使用for-in,不過這種遍歷方式會把原型上的屬性和方法也給遍歷出來,固然咱們能夠經過hasOwnProperty
來過濾掉除了實例對象的數據,可是for-of在object對象上暫時沒有實現,可是咱們能夠經過Symbol.iterator給對象添加這個塑性,咱們就可使用for-of了,代碼以下ui
var p={
name:'kevin',
age:2,
sex:'male'
}
Object.defineProperty(p,Symbol.iterator,{
enumberable:false,
configurable:false,
writable:false,
value:function(){
var _this=this;
var nowIndex=-1;
var key=Object.keys(_this);
return {
next:function(){
nowIndex++;
return {
value:_this[key[nowIndex]],
done:(nowIndex+1>key.length)
}
}
}
}
})
}
//這樣的話就能夠直接經過for-of來遍歷對象了
for(var i of p){
console.log(i)
}
輸出的是:kevin,2,male
複製代碼
其實for-of的原理最終也是經過調用p[Symbol.iterator]()這個函數,這個迭代器函數返回一個next函數,for循環會不斷調用next 那麼知道原理以後,咱們能夠本身來調用iterator.next來實現循環this
var students = {}
students[Symbol.iterator] = function() {
let index = 1;
return {
next() {
return {done: index>100, value: index++}
}
}
}
var iterator = students[Symbol.iterator]();
var s=iterator.next();
while(!s.done) {
console.log(s.value);
s=iterator.next();
}
複製代碼
上例中使用 iterator.next 和 while 結合實現了 for循環。 除了使用iterator 以外,咱們還可使用 yield 語法來實現循環,yield相對簡單一些,只要經過 yield 語句把值返回便可:spa
let students = {
[Symbol.iterator]: function*() {
for(var i=0;i<=100;i++) {
yield i;
}
}
}
for(var s of students) {
console.log(s);
}
//這個yield其實最後返回的就是iterator函數
複製代碼