js学习-遍历器(Iterator)

212 阅读2分钟

概念

MDN解释非标准。  Iterator 函数是一个 SpiderMonkey 专有特性,并且会在某一时刻被删除。为将来使用的话,请考虑使用 for..of 循环和  迭代协议。(emmm 读了一遍,听君一席话,如听一席话!啥也没读懂

其实遍历器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。

再简单来说Iterator接口就是可遍历的标志,各种数据结构遍历靠的都是它!

关于详细概念可以参考 MDN ,这里主要分享一些学习中的体会。


作用

Iterator的作用有三个:

  • 为各种数据结构,提供一个统一的、简便的访问接口;
  • 使得数据结构的成员能够按某种次序排列;
  • ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。

在ES6中,数据结构原生就部署Iterator接口的有数组、某些类似数组的对象(Array,Map,Set,String,TypedArray,函数的 arguments 对象,NodeList 对象,字符串)、SetMap结构。它们即不用任何处理,就可以被for...of循环遍历。

为对象添加Iterator接口的例子

let obj1 = {
  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 };
        }
      }
    };
  }
};
let obj2={ 0:"hello", 1:"word" }

//遍历模拟了iterator接口的对象obj1
for (const key of obj1) {
  console.log(key); 
}
//遍历没有iterator接口的对象obj2
for (const key of obj2) {
  console.log(key);
}

运行结果

image.png

可以看出obj1成功遍历,而obj2遍历报错(obj2不存在iterator接口,不能被遍历)

类数组对象调用数组的Symbol.iterator方法

let iterable = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3,
  [Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {
  console.log(item); // 'a', 'b', 'c'
}

学习中遇到的困难

学习Array.keys()(keys() 方法返回一个数组索引的迭代器。)时,遇到这样两个例子,

1:
var array = ["abc", "xyz"]; 
var iterator = array.keys(); 
console.log(iterator); //[ Object [Array Iterator] {} ] 自己尝试的
console.log(iterator.next()); // Object {value: 0, done: false} 
console.log(iterator.next()); // Object {value: 1, done: false} 
console.log(iterator.next()); // Object {value: undefined, done: false}
2:
var array = ["abc", , "xyz"]; 
var iterator = [...array.keys()]; 
console.log(iterator); // [0, 1, 2]

为什么例1中的iterator = array.keys()array数组索引的迭代器,通过iterator.next()调用下一个元素,此时输出iterator[ Object [Array Iterator] {} ],但是例2中的iterator = [...array.keys()],输出iterator却为[0, 1, 2],想不通为什么,后来查了一圈才知道ES6-扩展运算符(...)会默认调用Iterator接口(即Symbol.iterator方法),所以可以输出[0, 1, 2]

除了ES6-扩展运算符(...)还有一些会默认调用Iterator接口的场合

-   for...of
-   解构赋值
-   扩展运算符(...)
-   yield*_yield*后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。
-   由于数组的遍历会调用遍历器接口,所以任何接受数组作为参数的场合,其实都调用。