ES6之Iterator遍历器

遍历器(Iterator)是一种接口,为各类不一样的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就能够完成遍历操做(即依次处理该数据结构的全部成员)。数组

其实iterator在之前是内置在JavaScript中,主要是Array和Object表示的集合数据结构使用。ES6新增了map和set数据结构,这样就有了四种数据集合。这样就须要一个统一接口机制来处理不一样的数据结构。Iterator就是这个做用。bash

Iterator 的做用有三个:数据结构

为各类数据结构,提供一个统一的、简便的访问接口;函数

使得数据结构的成员可以按某种次序排列;ui

ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。spa

Interator内部遍历过程:prototype

建立一个指针对象,指向当前数据结构的起始位置。遍历器对象本质上,就是一个指针对象。指针

第一次调用指针对象的next方法,能够将指针指向数据结构的第一个成员。code

第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。orm

不断调用指针对象的next方法,直到它指向数据结构的结束位置。

每一次调用next方法,都会返回数据结构的当前成员的信息。就是返回一个包含value和done两个属性的对象。value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。

咱们说了,Iterator 接口的目的,就是为全部数据结构,提供了一种统一的访问机制,主要提供给ES6的for of使用。当咱们使用for of的时候会自动寻找Interator接口。一种数据结构只要部署了Iterator接口,咱们就称之为可遍历的(iterable)。

ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具备Symbol.iterator属性,就能够认为是“可遍历的”(iterable)。

Symbol.iterator属性自己是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。属性名Symbol.iterator,它是一个表达式,返回Symbol对象的iterator属性,这是一个预约义好的、类型为 Symbol 的特殊值,因此要放在方括号内。

ES6 的有些数据结构原生具有 Iterator 接口(好比数组),即不用任何处理,就能够被for...of循环遍历。缘由在于,这些数据结构原生部署了Symbol.iterator属性,另一些数据结构没有(好比对象)。凡是部署了Symbol.iterator属性的数据结构,就称为部署了遍历器接口。调用这个接口,就会返回一个遍历器对象。

咱们给一个obj部署:

const obj = {  

  [Symbol.iterator] : function () {    

    return {      

      next: function () {         

       return {            

        value: 1,           

         done: true        

        };      

      }    

    };  

  },  

  a: 1};

console.log(obj[Symbol.iterator]().next());//{value: 1, done: true}
复制代码

原生具有 Iterator 接口的数据结构以下。

Array

Map

Set

String

TypedArray

函数的 arguments 对象

NodeList 对象

咱们使用数组的Symbol.iterator属性:

var arr = [1, 2];

var arrIter = arr[Symbol.iterator]();

console.log(arrIter.next());//{value: 1, done: false}

console.log(arrIter.next());//{value: 2, done: false}

console.log(arrIter.next());//{value: undefined, done: true}
复制代码

对于原生部署 Iterator 接口的数据结构,不用本身写遍历器生成函数,for...of循环会自动遍历它们。除此以外,其余数据结构(主要是对象)的 Iterator 接口,都须要本身在Symbol.iterator属性上面部署,这样才会被for...of循环遍历。

要注意的是,部署了Symbol.iterator属性的并不能直接用for of循环,想要使用for of循环还须要在Symbol.iterator属性上部署遍历器生成方法。这边分享相似数组的对象调用数组的Symbol.iterator例子,其余的能够自行研究:

var iterable = {  

  0: 'a',  

  1: 'b',  

  2: 'c',  

  length: 3,  

  [Symbol.iterator]: Array.prototype[Symbol.iterator]

};

for (var item of iterable) {  

  console.log(item); // a b c

}
复制代码

普通对象这样使用是没有效果的。

虽然遍历器接口Iterator(就是Symbol.iterator)是给for of使用,可是其余不少会默认调用Symbol.iterator方法:

解构赋值、扩展运算符、yield*、Array.form、Map()、Set()、WeakSet()、WeakMap()、Promise.all()、Promise.race()等。

字符串是一个类数组,原生具备Iterator接口:

var str = 'abc';

var strIter = str[Symbol.iterator]();

console.log(strIter.next());//{value: "a", done: false}

console.log(strIter.next());//{value: "b", done: false}

console.log(strIter.next());//{value: "c", done: false}

console.log(strIter.next());//{value: undefined, done: true}
复制代码

遍历器对象除了具备next方法,还能够具备return方法和throw方法。若是你本身写遍历器对象生成函数,那么next方法是必须部署的,return方法和throw方法是否部署是可选的。

return方法的使用场合是,若是for...of循环提早退出(一般是由于出错,或者有break语句),就会调用return方法。若是一个对象在完成遍历前,须要清理或释放资源,就能够部署return方法。throw方法主要是配合 Generator 函数使用

一个数据结构只要部署了Symbol.iterator属性,就被视为具备 iterator 接口,就能够用for...of循环遍历它的成员。也就是说,for...of循环内部调用的是数据结构的Symbol.iterator方法。

for...of循环可使用的范围包括数组、Set 和 Map 结构、某些相似数组的对象(好比arguments对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串。

var str = 'abc';

for(var val of str){  

  console.log(val);

}
复制代码

有了for of,不少遍历的操做均可以使用,配合entries、keys、values,好比对象不能直接用for of遍历,咱们能够用keys方法把对象的键变成数组去遍历。

相对于其余遍历方法,for of会有一些优点,最大的优点我以为就是提供了遍历全部数据的统一操做接口。

相关文章
相关标签/搜索