专栏首页coding个人笔记ES6之Iterator遍历器

ES6之Iterator遍历器

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

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

Iterator 的作用有三个:

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

使得数据结构的成员能够按某种次序排列;

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

Interator内部遍历过程:

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

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

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

不断调用指针对象的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会有一些优势,最大的优势我觉得就是提供了遍历所有数据的统一操作接口。

(完)

本文分享自微信公众号 - coding个人笔记(gh_2ce38b49dae1),作者:wade

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-05-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Vuex之getter

    Vuex提供给我们一个Getter方法,主要就是为了在数据派生一些状态,简单来说就是想要通过判断进行过滤。

    wade
  • ES6之symbol

    ES6引入了一种新的原始数据类型Symbol,是第七种数据类型,表示独一无二的值。语法:

    wade
  • Vuex之结构

    之前整理了vuex的使用场景,现在开始学习学习怎么使用。我会根据官网api来重新学习一遍。

    wade
  • 安装声卡驱动的体会

    临时用一台机器(Dimension C521),想听一下张国荣的《当爱已成往事》,却发现系统找不到声卡,放不出声音。

    贰师兄TEN
  • C++核心准则C.42:如果构造函数不能生成合法对象就抛出异常

    Leaving behind an invalid object is asking for trouble.

    面向对象思考
  • JavaScript第十六弹——ES6(5)新成员Set & Map

    Hello小伙伴们,今天我们先把扩展放一放,为大家隆重介绍我们ES6新添加的两位成员——Set和Map!我们将分别从它们的基础用法、常用方法、遍历方法和特殊对象...

    萌兔IT
  • FFmpeg深度学习模块的历史、现状和计划

    很高兴能有机会在LiveVideoStock做有关于FFmpeg深度学习模块相关内容的技术分享。

    LiveVideoStack
  • Git prev & next

    When you are doing a talk with a demo in several steps, it can be practical to h...

    iOSDevLog
  • Python脚本BUG引发学界震动,影响有多大?

    近日一篇“A guide to small-molecule structure assignment through computation of (1H a...

    AI科技大本营
  • 在CentOS 7上离线安装Docker

    https://download.docker.com/linux/centos/7/x86_64/stable/Packages/

    田春峰-JCJC错别字检测

扫码关注云+社区

领取腾讯云代金券