15Iterator和for方法

Iterator 概念

遍历器本质上就是一个指针对象

  1. 只有布置了遍历器接口,才可遍历。遍历器接口是[Symbol.iterator]

Iterator 作用

  1. 为各种数据结构提供一个统一的访问接口
  2. 使得数据结构的成员能够按照某种次序排序
  3. for of提供接口

Iterator 遍历过程

  • 创建一个指针对象,指向当前数据结构的起始位置
  • 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。返回数据结构的当前成员,具体就是一个包含valuedone的对象。
  • 不断调用指针对象的next方法,直到它指向数据结构的结束位置

默认 Iterator 接口

注意,对象没有Iterator接口

  1. 原生具备 Iterator 接口的数据结构如下
  • Array
  • Set,类似数组,但是成员的值是唯一的
  • Map,类似对象,但是"键"的范围不限于字符串,各种类型的值都可以当作键
  • String
  • TypedArray
  • 函数的 arguments 对象
  • NodeList 对象(类数组对象)
  1. object 不具备原生Iterator接口,需要在[Symbol.iterator]上布置。生成的每项形式为[key,val]
// 为一个类数组对象布置 Iterator 接口
let obj = {
  0:'y',
  1: 'f',
  length: 2,
  [Symbol.iterator]() {
    const self = this;
    let index = 0;
    return {
      next() {
        if (index < self.length) {
          return {
            value: [index,self[index++]],
            done: false
          };
        } else {
          return { value: undefined, done: true };
        }
      }
    };
  }
};
// 布置到 Object 上
Object.prototype[Symbol.iterator] = function () {
}

通过遍历器实现指针结构的例子

// 指针结构
// 数据结构
function Obj(value) {
    this.value =value;
    this.next = null;
}
// 布置遍历接口
Obj.prototype[Symbol.iterator] = function () {
    var iterator = { next: next };

    var current = this;
    function next() {
        if (current) {
            val value = current.value;
            current = current.next;
            return { done: false, value: value }
        } else {
            return { done: true }
        }
    }

    return iterator;
}
var one = new Obj(1);
var two = new Obj(2);
var three = new Obj(3);

one.next = two;
two.next = three;

for (var i of one) {
    console.log(i);
}

生成 Iterator 方式

var arr = [1,2,3];
var iterator = arr[Symbol.iterator]();

默认调用Iterator接口的场合

  1. 解构赋值
  • 对数组和 Set 解构进行解构赋值时
  1. 扩展运算符
  • ...使用扩展运算符
  1. yield*
  2. 其他场合
  • for of
  • Array.from()
  • Map()
  • Set()
  • WeakMap()
  • WeakSet()
  • Promise.all()
  • Promise.race()
// 解构赋值
let set = new Set().add('a').add('b').add('c');
let [x,y] = set;

字符串的 Iterator 接口

// 使用字符串原生的遍历器接口
var str = 'hi';
var iterator = str[Symbol.iterator]();

iterator.next()  // { value: "h", done: false }
iterator.next()  // { value: "i", done: false }
iterator.next()  // { value: undefined, done: true }

遍历器对象的return(),throw()

for of中使用break或者continue提前退出,会调用return方法

//遍历器,必须返回一个包含next方法的对象
// 可选的返回一个包含了throw方法和return方法的对象
function ite() {
    return {
        next() {
            return {done: false}
        },
        return() {
            file.close();
            return { done: true }
        }
    }
}
// throw 方法不常用

for of循环

数组

// for in 获取的是键名,包含了数组的索引和属性,甚至原型上的属性
var arr = [7,9,0];
arr.foo = 'bar';
for (let i in arr) {
    console.log(i);  // '0','1','2','foo'
}
// for of 获取的是数组每项的值
for (let i of arr) {
    console.log(i);  // '7','9','0'
}

Set 和 Map 解构

计算生成的数据结构

数组,Set,Map部署了下面三个方法,这些方法都返回遍历器对象

  1. entries()
  2. keys()
  3. values()

类似数组的对象

并不是所有类似数组的对象都有 Iterator 接口,可以使用Array.from将其转化为数组,再使用for of方法

对象

普通对象,不能直接使用for of,会报错。解决方法:

  1. 使用Object.keys()生成一个由对象属性值组成的数组,再使用for of
  2. 另一个方法使用Generator将对象包装一下
  3. 可以在对象实例上直接布置[Symbol.iterator],也可以在对象原型链上布置[Symbol.iterator]。部署类数组对象的[Symbol.iterator]和普通对象的[Symbol.iterator]方法不同
// 使用 Generator 将对象包装一下
function* entries(obj) {
    // 使用的是Object.keys而不是for in 循环
  for (let key of Object.keys(obj)) {
    yield [key, obj[key]];
  }
}

for (let [key, value] of entries(obj)) {
  console.log(key, '->', value);
}

你可能感兴趣的:(15Iterator和for方法)