es6的学习笔记(四):iterators and iterable

iterator本质上是一种协议,用于定义适用于所有对象的迭代

迭代规则

所有的对象,都可以使用迭代协议,只要为它添加一个属性名为[Symbol.iterator],属性值为遵循协议的一个函数就可以使用迭代协议。

var s={
  name:[1,2,3,4,5],
  value:0,
  [Symbol.iterator]:function(){   //绑定一个方法,该方法返回一个具有next方法的对象。
    return {
      next:()=>{
        if(this.value==this.name.length){
          this.value = 0;          //此处需要将控制迭代的数值清零,不然只能迭代一次,亲测
          return {value:undefined,done:true};
        }
        else {
          return {value:this.name[this.value++],done:false};
        }
      }
    }
  }
}
for(let value of s){
  console.log(value);//输出1,2,3,4,5
}

当为对象s绑定了属性名为[Symbol.iterator],且属性值符合一定的要求,就可以使用for of来进行迭代。在该方法中,应该符合以下几个规则:

  1. 返回值是next函数
  2. next函数没有参数,返回值是一个对象{value,done}
  3. done表示该序列是否迭代结束,是一个boolean类型
  4. value是当前的输出值
    注意迭代器结束时需将控制迭代的数字还原,不然迭代器只能使用一次,其实也不算使用一次,它可以继续使用,只是使用一次之后如果不归零,再次使用直接就结束,也就没有任何数值输出,容易出错而已
    这样,就可以使用for of 语句迭代,数值就是next方法中的value,而结束就是根据done的值来判断是否结束。

自带迭代属性的对象

上述的方法使得普通的对象也可以进行迭代,不过,还有一些预定义的对象也具有迭代性。比如:Array,String,DOM中的NodeList,arguments都是默认可以迭代的,也就是可以直接使用for of结构。

将可迭代的对象还原为数组

有两种方法,一种是spread操作符。一种是Array.form函数。Array.from除了可以把可迭代对象转换成数组,也可以把类数组对象转换成数组。类数组对象就是属性名为0,1,2,3,4并且具有length属性的对象

var s={
  name:[1,2,3,4,5],
  value:0,
  [Symbol.iterator]:function(){   //绑定一个方法,该方法返回一个具有next方法的对象。
    return {
      next:()=>{
        if(this.value==this.name.length){
          this.value = 0;
          return {value:undefined,done:true};
        }
        else {
          return {value:this.name[this.value++],done:false};
        }
      }
    }
  }
}
console.log(...s);//此处直接使用...操作符,输出1 2 3 4 5,此处是没有,的,因为并没有转换成数组,相当于连续输出了
console.log(Array.from(s));//此处输出1,2,3,4,5
var q = [...s];//使用...操作符将s转换成数组
console.log(q);//输出1,2,3,4,5
for(let i in q)
  console.log(i)//输出0-4
console.log(Array.from({0:'a',1:'b',2:'c',length:3}));//此处输出a,b,c

无限序列

如果在next函数中,done变量始终是false,那么这个序列永远不会结束,同样的,如果对这个序列进行Array.from()或者[…]操作以及for of都会使程序崩溃。

const x = {
  [Symbol.iterator]:()=>{
    return {
      next:()=>{return {value:Math.random(),done:false}}
    }
  }
}
console.log(x[Symbol.iterator]().next().value)//不断执行,一直会产生一个新的随机数
for(let s of x)
  console.log(s)//后面的for循环一旦执行,浏览器的控制台就卡住,只能关闭重启

const [one, another] = random  //可以使用这样的结构来访问有限的无限序列中的元素
console.log(one)
// <‐ 0.23235511826351285
console.log(another)
// <‐ 0.28749457537196577