ES6新特性 Iterator和for..of循环

Iterator

  • Iterator是ES6引入的一种新的遍历机制,迭代器有两个核心概念:

    • 迭代器是一个统一的借口,他的作用是使各种数据结构可被便捷地访问。
      迭代器是通过一个键位Symbol.iterator的方法来实现。
    • 迭代器是用于遍历数据结构元素的指针(类似于数据库中的游标cursor)。
  • 迭代过程

    1. 获取迭代器(指向当前数据结构的起始位置)。
    • 通过Symbol.iterator创建迭代器。
      • 可迭代对象:iterable
      • 其迭代器:iterable[Symbol.iterator]()(String, Array, Set, Map)通用
      • 可返回其迭代器的方法:iterator[Symbol.iterator]
    • 通过对象的某些方法返回迭代器对象。如:
      • arr.values()

      • set.keys(), set.values()

      • map.keys(), map.values(), map.entries()

      • String对象没有实例方法用于返回其迭代器对象,所以只能用Symbol.iterator

    1. 多次调用iterator.next()向下迭代指向下一个位置。
    • next()方法会返回当前位置的对象,然后指针后移。
    • 对象的格式:{value: [...], done: 布尔值},其中
      • value: 当前元素的值的数值。Map的为[key, value],其他的value一般长度为1。
      • done: 判断遍历是否结束(是否移动到了最后一个元素)。
    1. donetrue时遍历结束。

如要重新迭代,需要重新获取迭代器(从第1步重新开始)。

可迭代的数据结构

String
Array
Set
Map
DOM元素(开发中。。。)

  • for..of
    for (let e of obj) {
      console.log(e);
    }
    
    其中:
    • e
      • 可以直接为e
      • 也可以是具体每个元素的value形式如map队形的[key, value]
    • obj
      • 可以直接是对象本身(如map)
      • 也可以是对象的迭代器iterator
        (如map.keys(), map.values(), map.entries(), map[Symbol.iterator]())。

不同搭配,性能可能会有所差异。

  • 两种方式迭代访问可迭代数据解构
    iterator.next()
    for..of

迭代访问

以下依次为String, Array, Set, Map类对象的 迭代器访问for…of循环访问。

  • String

    var str = "hello";
    var iterator = str[Symbol.iterator]();
    for (let i = 0; i < str.length; i++) {
      console.log(i, iterator.next().value);
      // 或value[0],因为此时value数组只有一个元素。
    }
    
    // for (let ch of str[Symbol.iterator]) {  
    for (let ch of str) {   // 也可以是str
      console.log(ch);
    }
    
  • Array

    var arr = Array.from("abcd");
    var iterator = arr.values();  // 返回Array Iterator对象
    for (let i = 0; i < arr.length; i++) {
      console.log(i, iterator.next().value);  // 或value[0]
    }
    
    // arr或arr.values()或arr[Symbol.iterator]皆可。
    for (let e of arr) {
      console.log(e);
    }
    
  • Set

    var set = new Set().add("a").add("b").add("c"); // 链式调用
    var iterator = set[Symbol.iterator]();
    for (let i = 0; i < set.size; i++) {
      console.log(i, iterator.next().value); // 或value[0]
    }
    
    // set, set.keys(), set.values(), set[Symbol.iterator]皆可。
    for (let e of set) {
      console.log(e);
    }
    
  • Map
    Map类对象除了可以用map[Symbol.iterator]()获取其迭代器MapIterator
    Map类对象有3种成员方法也可以获取(针对其元素不同位置的)迭代器:

    • map.keys()
    • map.values()
    • map.entries()
      另外,也可通过map[Symbol.iterator]()获取其迭代器MapIteraor。 **NOTE**mapSymbol.iterator相当于map.entries(),同时遍历元素的key-value`对。

遍历方式同上,唯一不同的是map.entries()返回的迭代器的next()方法返回的对象:
{value: [key, value], done: 布尔值}中,value为长度为2的数组。

var map = new Map().set(1, "one").set(2, "two");
var iterator = map.entries();
undefined
for (let i = 0; i < map.size; i++) {
  console.log(i, iterator.next().value)
}

// 两种for..of循环
for (let entry of map) {
  console.log(entry);
}
for (let [key, value] of map) {
  console.log(key, value);
}

JS中Map对象的创建,遍历(7种)和使用(增删改查)

NOTE

  • 函数内的隐式参数arguments其实是Array类型,所以也用迭代器迭代。
  • for..of
  • for (e of obj)中的e可以用关键字var, let, const声明。
    • var 迭代不会每次都创建一个新的存储空间,但全局有效(for..of循环外e依旧可用)
    • let, const每次迭代创建一个新的存储空间,但可以保证作用域的迭代内部。
      且用const声明的话,e值不可修改。
  • object不可迭代
    可迭代的数据结构有:String, Array, Set, Map
    不可迭代的有:Object,以及ES6新增的WeakSet, WeakMap(未定义obj[Symbol.iterator]())。
  • arrayLike类数组对象
    因为object无法被迭代。
    但是有一种特殊对象,其属性名称中只有一个length(属性值为数值类型),其他属性名称都是数值,类似于数组的索引(0, 1, 2, 3等)。
    这种对象可以用Array.from(obj)转换为数组对象,然后就可以对数组进行迭代。
var arrayLike = {length: 4, 0:"zero", 1:"one", 3:"four"}; // Object
var arr = Array.from(arrayLike);  // Array
console.log(arr);
// (4) ["zero", "one", undefined, "four"]

之后就可以对新得到的数组arr进行遍历

你可能感兴趣的:(JS)