Iterator和for...of

176 阅读2分钟

  Iterator是一种接口,为不同的数据结构提供统一的数据访问机制。   for...of是ES6引入的一种遍历所有数据接口的方法。

Iterator有何用途

  1. 为各种数据提供统一的接口;
  2. 使得数据结构的成员能够按照某种次序排列;
  3. 为for...of服务,供for...of消费。

Iterator概念

var it = makeIterator(['a', 'b']);

it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }

function makeIterator(array) {
  var nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length ?
        {value: array[nextIndex++], done: false} :
        {value: undefined, done: true};
    }
  };
}

注释:

  1. makeIterator函数是一个遍历器生成函数,作用就是返回一个遍历器对象it。
  2. next方法是用来移动位置的,每次调用都会返回一个对象{value:'', done:true/false},value就是返回当前遍历位置的值,done表示是否遍历结束。

Iterator接口实现

  一种数据结构只要部署了 Iterator 接口,我们就称这种数据结构是“可遍历的”(iterable)。ES6规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性。

  已默认部署 Iterator 接口的对象主要包括Array、String、Set、Map 、类似数组的对象(如arguments对象、DOM NodeList对象)。

  对象(Object)之所以没有默认部署 Iterator 接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定。

对象Iterator接口实现

let obj = {
  data: [ 'hello', 'world' ],
  [Symbol.iterator]() {
    const self = this;
    let index = 0;
    return {
      next() {
        if (index < self.data.length) {
          return {
            value: self.data[index++],
            done: false
          };
        } else {
          return { value: undefined, done: true };
        }
      }
    };
  }
};
for (var val of obj) {
  console.log(val);
} 
// 打印键值"hello""world"

Iterator应用场景

  1. 解构赋值
var iterableObj = {
    items: ['红','绿','蓝'],
    [Symbol.iterator]: function () {
        var self = this;
        var i = 0;
        return {
            next: function () {
                var done = (i >= self.items.length);
                var value = !done ? self.items[i++] : undefined;
                return {
                    done: done,
                    value: value
                };
            }
        };
    }}
    var [d,e] = iterableObj;
    console.log(d,e);//红 绿

  1. 扩展运算符(...)
  2. yield*

for...of运行机制

  执行for...of其实就是调用遍历器生成函数,然后依次执行遍历器对象的next方法,将next方法返回的值(value)赋值给for...of中的变量。

for in和for of

  1. for in遍历数组的键名,for of 遍历的是数组的键值。
var myObject ={
   a:'1',
   b:'2',
   c:'3'
}
myObject.__proto__.d = '4';
for (var key in myObject) {
    if(myObject.hasOwnProperty(key)){
        console.log(key);
    }
}
// 只打印实例属性的键名"a""b""c"
var myArray = ['1','2','3']

for (var val of myArray) {
    console.log(val);
} 
// 打印键值"1""2""3"
  1. for in

(1)遍历顺序不一定

(2)遍历所有可枚举的属性,包括原型上的属性和方法

  for in更适合遍历对象,不适合遍历数组;遍历对象时,如果不想要原型上的属性和方法,可以通过hasOwnProperty来判断该属性是不是实例的属性,这实际上跟Object.keys(myObj)得到的结果一样。

  1. for of

  更适合遍历数组、数组对象、字符串、Map、Set等拥有迭代器对象的集合,但是不能遍历对象,如果要遍历,需要实现Symbol.interator属性;

  相对于forEach,可以响应break、continue、return语句。