ES6系列教程第二篇--Iterator 详解

一、什么是for-of循环

  对于如下一个数组,遍历其中的值方法有哪些?

var arr = ['a', 'b', 'c'];

首先想到的可能就是如下这种,这也是js最原始的遍历方法,和java的语法一样。

 var arr = ['a', 'b', 'c'];
 for (var i=0;i

如果你了解ES5,还可以写出for-in的方法。

var arr = ['a', 'b', 'c']; 
for(var i in arr){
   console.log(arr[i]);
}

今天为大家再介绍一种for-of的遍历方法

var arr = ['a', 'b', 'c']; 
for(var ch of arr){
    console.log(ch);
}

在这个例子中,大家注意到使用for-of时,ch不是数组的索引值,所示其中的value值。

那有了for-in,为什么还要设计for-of呢,或者说for-of有什么独特的地方。继续实例:

let arr = "abc";
for( var char of arr){
    console.log(char);
}

此时,可以将a,b,c输出,但是for-in是无能为力的。其中for-of不仅能对数组和字符串进行遍历。还可以适用以下的集合:

Map

Set

NodeList

其中Map,Set是ES6新增的特性,现在不了解也没关系,我们稍后单独讲。NodeList是DOM对象集合,有兴趣的可能查阅资料了解,不在这里展开讨论。

二、迭代器(Iterator)实现原理

再看一个普通的字面量对象例子:

var obj={0:"rrr",1:"444"};
   for(var value of obj){
     console.log(value);
   }

    运行后发现报错,表明这个字面量对象是不可遍历的。那能否像Array,String等对象一样支持for-of遍历呢?答案是可以的,Array,String等对象之所以可遍历,是因为在他们的原型上,实现了迭代器(Iterator)的接口。

  那如何实现迭代器(Iterator)接口呢,只需要在这个对象中实现[Symbol.iterator]属性方法,[Symbol.iterator]这个属性名ka看起来怪怪的,Symbol是ES6表示唯一性的标识符,标准委员会是为了避免命名的冲突,所以才这样命名,大家作为一个唯一的字符串理解即可,不去深究。下面我们来实现[Symbol.iterator]属性。如下:

var obj={
    0:"rrr",
    1:"444",
    //实现[Symbol.iterator]属性方法
    [Symbol.iterator]:function(){
        const self = this;
        let index=0;
        return {
          next:function(){//实现next
            if(index<2){
              return {//遍历中
                value:self[index++],
                done: false//表示遍历没有结束,done设置为fasle
              }
            }else{
              return{//遍历结束
                value:undefined,//结束后,返回undefined
                done: true//done设置为true,表示遍历结束
              }
            }
          }
        }
     } 
    };
   for(var value of obj){
     console.log(value);//"rrr","444"
   }

  此时正确的遍历了obj,打印了obj的属性的值。再来看下[Symbol.iterator]属性函数体,返回了next方法,next方法中遍历了此obj的属性对象,并返回字面量对象{value:xxx,done:xxx}这种结构对象,在遍历过程中,value返回对应属性值,且done设置为false;当遍历结束后,value返回undefined,且done设置为true。

var it = obj[Symbol.iterator]();
console.log(it.next());//{value: "rrr", done: false}
console.log(it.next());//{value: "444", done: false}
console.log(it.next());//{value: undefined, done: true}

   这就是for-of的原理,每次遍历都会调用该对象的[Symbol.iterator]属性的next方法,当返回{value: undefined, done: true}后,表示遍历结束。

所以讲到这,各位道友是否就明白了,任何对象要变成可遍历的对象,只需要实现[Symbol.iterator]属性方法,定义其中的next方法即可。

三、break,continue

  学过java的道友们,对break,continue应该再熟悉不过了,意义我就不再阐述。for-of对于for-in的优点就是它能支持这些语句。我们接着往下看。

let arr = "abc";
for( var char of arr){
      console.log(char);//"a"
      break;
}

仅输出了“a”就跳出了循环。有兴趣的道友可以再实验下continue,看看效果。

好了,我们将上面obj的实例再修改下,使其支持这些语句

var obj={
    0:"rrr",
    1:"444",
    //实现[Symbol.iterator]属性方法
    [Symbol.iterator]:function(){
        const self = this;
        let index=0;
        return {
          next:function(){//实现next
            if(index<2){
              return {//遍历中
                value:self[index++],
                done: false//表示遍历没有结束,done设置为fasle
              }
            }else{
              return{//遍历结束
                value:undefined,//结束后,返回undefined
                done: true//done设置为true,表示遍历结束
              }
            }
          },
         return:function() {//增加return,支持continue,break
          return { done: true };
        }
        }
     } 
    };
   for(var value of obj){
     console.log(value);//"rrr"
     break ;
   }

此时仅输出了"rrr"就跳出了循环,在执行break时,内部调用了return的方法,返回了{done:false},continue也是如此。

四、总结

  主要学些了for-of循环,并通过这个循环讲述了迭代器(Iterator)的实现原理。for-of的用处还是很强大的,可以和我们下一章节要介绍的Generator对象很好的结合。

上一篇:ES6系列教程第一篇--Promise详解                             下一篇:ES6系列教程第三篇--Generator 详解

你可能感兴趣的:(前端技术,JavaScript,ES6,Iterator,for,of)