遍历器Iterator访问数据集合的统一接口的方法

这篇文章给大家介绍的内容是关于遍历器iterator访问数据集合的统一接口的方法,有着一定的参考价值,有需要的朋友可以参考一下。

导语

遍历器Iterator是ES6为访问数据集合提供的统一接口。任何内部部署了遍历器接口的数据集合,对于用户来说,都可以使用相同方式获取到相应的数据结构。如果使用的是最新版Chrome浏览器,那么你要知道——我们所熟悉的数组小姐,已悄悄的打开了另一扇可抵达她心扉的小径。

1 正题

某个数据集合部署了Iterator接口,是指其Symbol.iterator属性指向一个能返回Iterator接口的函数。任何默认使用遍历器访问数据集合的方法,都会调用此属性以得到遍历器对象,再按照设定的顺序依次访问该数据结构的成员(关于Symbol.iterator请看最后一节的延伸阅读)。比如原生数组的遍历器为[][Symbol.iterator],也可以直接通过其构造函数的原型获取Array.prototype[Symbol.iterator]。

1.1 基本行为

调用Iterator接口会返回一个新的遍历器对象(指针对象)。  
对象中必然有next方法,用于访问下一个数据成员。指针初始时指向当前数据结构的起始位置。

第一次调用对象的next方法,指针指向数据结构的第一个成员。  
第二次调用对象的next方法,指针指向数据结构的第二个成员。  
不断的调用对象的next方法,直到它指向数据结构的结束位置。

每次调用next方法,都会返回相同的数据结构:{ value, done }。  
其中value表示当前指向成员的值,没有则为undefined。  
其中done是一个布尔值,表示遍历是否结束,结束为true,否则false。

遍历器接口的标准十分简洁,不提供诸如:操作内部指针、判断是否有值等等方法。只需要一直不断的调用next方法,当done为false时获取当时的value,done为true时停止即可。第一次接触遍历器的行为模式是在2016的冬天,那时底蕴不够鸡毛也没长全,理解不了简洁性的适用和强大。直到现在——在即将打包被迫离开公司的前夕才蓦然的醒觉。多么痛的领悟啊。

let iterator = [1, 2, 3][Symbol.iterator]();console.log( iterator.next() ); // {value: 1, done: false}console.log( iterator.next() ); // {value: 2, done: false}console.log( iterator.next() ); // {value: 3, done: false}console.log( iterator.next() ); // {value: undefined, done: true}

登录后复制

1.2 简单实现

面向不同的数据结构,有不同的遍历器实现方法,我们简单的实现下数组的遍历器方法。

let res = null;let iterator = myIterator([3, 7]);console.log( iterator.next() ); // {value: 3, done: false}console.log( iterator.next() ); // {value: 7, done: false}console.log( iterator.next() ); // {value: undefined, done: true}function myIterator(array = []) {  let index = 0;  return {    next() {      return index < array.length         ? { value: array[index++], done: false }        : { value: undefined, done: true };    }  };}

登录后复制

1.3 return & throw

除了为遍历器对象部署next方法,还可以有return和throw方法。其中return方法会在提前退出for of循环时(通常是因为出错,或触发了break语句)被调用。而throw方法主要是配合Generator函数使用,一般的遍历器对象用不到这个方法,所以不予介绍。

let obj = {  [Symbol.iterator]() {    let index = 0;    let array = [1, 2, 3];    return {      next() {        return index < array.length           ? { value: array[index++], done: false }          : { value: undefined, done: true };      },      return() {        console.log('Trigger return.');        return {};      }    };  }};for (let v of obj) {  console.log(v); // 打印出:1, 2, 3,没触发 return 函数。}for (let v of obj) {  if (v === 2) break;  console.log(v); // 打印出:1,之后触发 return 函数。}for (let v of obj) {  if (v === 3) break;  console.log(v); // 打印出:1, 2,之后触发 return 函数。}for (let v of obj) {  if (v === 4) break;  console.log(v); // 打印出:1, 2, 3,没触发 return 函数。}for (let v of obj) {  if (v === 2) throw Error('error');  console.log(v); // 打印出:1,之后触发 return 函数,并报错停止执行。}

登录后复制

2 原生支持

2.1 默认持有遍历器

原生默认持有遍历器接口的数据结构有:  
基本类型:Array, Set, Map(四种基本数据集合:Array, Object, Set 和 Map)。  
类数组对象:arguments, NodeList, String。

let iterator = '123'[Symbol.iterator]();console.log( iterator.next() ); // {value: "1", done: false}console.log( iterator.next() ); // {value: "2", done: false}console.log( iterator.next() ); // {value: "3", done: false}console.log( iterator.next() ); // {value: undefined, done: true}

登录后复制

遍历器与先前的遍历方法  
一个数据集合拥有遍历器接口,并不意味着所有遍历它的方法都是使用此接口。实际上,只有ES6新增的几种方式和某些方法会使用,下面会有介绍。以数组来说,对其使用for和for of虽然可访问到相同的成员,但是实际的操作方式却不同。

// 改变数组默认的遍历器接口。Array.prototype[Symbol.iterator] = function () {  let index = 0;  let array = this;  console.log('Use iterator');  return {    next() {      return index < array.length         ? { value: array[index++], done: false }        : { value: undefined, done: true };    }  }};let arr = [1, 2];for (let v of arr) {  console.log(v); // 打印出 Use iterator, 1, 2。}for (let i = 0; i  {  console.log(d); // 打印出 1, 2。});

登录后复制

对象没有默认的遍历器接口  
为什么对象没有默认的遍历器接口?这要从两方面说明。一为遍历器是种线性处理结构,对于任何非线性的数据结构,部署了遍历器接口,就等于部署一种线性转换。二是对象本来就是一个无序的集合,如果希望其有序,可以使用Map代替。这即是各有其长,各安其职。屎壳郎如果不滚粪球而去采蜜,那,呃,花妹妹可能就遭殃咯。

自行生成的类数组对象(拥有length属性),不具备遍历器接口。这与String等原生类数组对象不同,毕竟人家是亲生的,一出生就含着金钥匙(也不怕误吞)。不过我们可以将数组的遍历器接口直接应用于自行生成的类数组对象,简单有效无副作用。

let obj = {  0: 'a',  1: 'b',  length: 2,  [Symbol.iterator]: Array.prototype[Symbol.iterator]};let iterator = obj[Symbol.iterator]();console.log( iterator.next() ); // {value: "a", done: false}console.log( iterator.next() ); // {value: "b", done: false}console.log( iterator.next() ); // {value: undefined, done: true}

登录后复制

为对象添加遍历器接口,也不影响之前不使用遍历器的方法,比如for in, Object.keys等等(两者不等同)。

let obj = {  0: 'a',  1: 'b',  length: 2,  [Symbol.iterator]: Array.prototype[Symbol.iterator]};console.log( Object.keys(obj) ); // ["0", "1", "length"]for (let v of obj) {  console.log(v); // 依次打印出:"a", "b"。}for (let k in obj) {  console.log(k); // 依次打印出:"0", "1", "length"。}

登录后复制

2.2 默认调用遍历器

for of  
for of是专门用来消费遍历器的,其遍历的是键值(for in遍历的是键名)。

for (let v of [1, 2, 3])  {  console.log(v); // 依次打印出:1, 2, 3。}

登录后复制

扩展运算符  
无论是解构赋值或扩展运算都是默认调用遍历器的。

let [...a] = [3, 2, 1]; // [3, 2, 1]let b = [...[3, 2, 1]]; // [3, 2, 1]

登录后复制

yield*  
在Generator函数中有yield*命令,如果其后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。

for (let v of G()) {  console.log(v); // 依次打印出:1, 2, 3, 4, 5}function* G() {  yield 1;  yield* [2,3,4];  yield 5;}

登录后复制

其它场合  
有些接受数组作为参数的函数,会默认使用数组的遍历器接口,所以也等同于默认调用。比如Array.from(), Promise.all()。

相关推荐:

angularjs关于页面模板清除的使用方法

在JS中用slice封装数组方法

以上就是遍历器Iterator访问数据集合的统一接口的方法的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2745736.html

(0)
上一篇 2025年3月8日 03:48:40
下一篇 2025年3月8日 03:48:52

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • React的使用:react框架的五大特点

    这篇文章给大家介绍的内容是关于react的使用:react框架的五大特点,有着一定的参考价值,有需要的朋友可以参考一下。 01. React 出现的时代背景 世界上的事情都有因才有果,一个框架的出现也必然离不开特定的时代背景。而对于 Rea…

    编程技术 2025年3月8日
    200
  • react的使用: React如何渲染UI

    这篇文章给大家介绍的内容是关于react的使用: react如何渲染ui,有着一定的参考价值,有需要的朋友可以参考一下。 01. React 渲染界面的方式 在 React 等大型前端框架出现之前,我们渲染 UI 元素的方式是使用字符串模板…

    编程技术 2025年3月8日
    200
  • React的使用:React组件内部的状态管理

    这篇文章给大家介绍的内容是关于React的使用:React组件内部的状态管理,有着一定的参考价值,有需要的朋友可以参考一下。 在本文中,我们将把目光聚焦于 React 组件内部的状态管理,去认识或重新思考以下三个核心概念: props 和 …

    编程技术 2025年3月8日
    200
  • vue-cli的单元测试的示例解析

    这篇文章给大家介绍的内容是关于vue-cli的单元测试的示例解析,有着一定的参考价值,有需要的朋友可以参考一下。 vue-cli的单元测试 最近项目开发临近结尾,反思之前做的不足的地方,想着应该引入测试类的做法,于是乎开始学习前端测试之类的…

    编程技术 2025年3月8日
    200
  • JavaScript中Object.defineProperty()方法的解析

    这篇文章给大家介绍的内容是关于javascript中object.defineproperty()方法的解析,有着一定的参考价值,有需要的朋友可以参考一下。 =与Object.defineProperty 为JavaScript对象新增或者…

    编程技术 2025年3月8日
    200
  • js如何实现将上传图片并且压缩的方法

    这篇文章给大家介绍的内容是关于js上传图片压缩,有着一定的参考价值,有需要的朋友可以参考一下。 js实现图片压缩后上传 用到的技术: canvas相关api html5的一些api 兼容性: 点击下载“嗨格式压缩大师”; h5没发现问题,p…

    编程技术 2025年3月8日
    200
  • js实现重建二叉树的算法解析

    这篇文章给大家介绍的内容是关于js实现重建二叉树的算法解析,有着一定的参考价值,有需要的朋友可以参考一下。 题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前…

    编程技术 2025年3月8日
    200
  • React中动画不生效的原因分析

    这篇文章给大家介绍的内容是关于react中动画不生效的原因分析,有着一定的参考价值,有需要的朋友可以参考一下。 项目中需要做这样的一个组件根据不同的数值,这个蓝色的条显示的宽度不同。这个其实很简单,我只要根据数据动态的计算它的宽度,生成节点…

    编程技术 2025年3月8日
    200
  • React Event事件注册的实现

    这篇文章给大家介绍的内容是关于react event事件注册的实现,有着一定的参考价值,有需要的朋友可以参考一下。 React 元素的事件处理和 DOM元素的很相似。但是有一点语法上的不同: React事件绑定属性的命名采用驼峰式写法,而不…

    2025年3月8日
    200
  • 原生JS如何动态加载JS和CSS文件以及代码脚本

    这篇文章给大家介绍的内容是关于原生js如何动态加载js和css文件以及代码脚本,有着一定的参考价值,有需要的朋友可以参考一下。 DOM readyState属性共5中状态 uninitialized:初始状态 loading:documen…

    编程技术 2025年3月8日
    200

发表回复

登录后才能评论