热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Iterator:接见数据鸠合的一致接口

导语遍历器Iterator是ES6为接见数据鸠合供应的一致接口。任何内部布置了遍历器接口的数据鸠合,关于用户来讲,都能够运用雷同体式格局猎取到响应的数据构造。假如运用的是最新版Ch

导语

遍历器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要领,当donefalse时猎取当时的valuedonetrue时住手即可。第一次打仗遍历器的行动形式是在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 ? { value: array[index++], done: false }
: { value: undefined, done: true };
}
};
}

1.3 return & throw

除了为遍历器对象布置next要领,还能够有returnthrow要领。个中return要领会在提早退出for of轮回时(平常是因为失足,或触发了break语句)被挪用。而throw要领主如果合营Generator函数运用,平常的遍历器对象用不到这个要领,所以不予引见。

let obj = {
[Symbol.iterator]() {
let index = 0;
let array = [1, 2, 3];
return {
next() {
return index ? { 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, SetMap)。
类数组对象: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新增的几种体式格局和某些要领会运用,下面会有引见。以数组来讲,对其运用forfor of虽然可接见到雷同的成员,然则现实的操纵体式格局却差别。

// 转变数组默许的遍历器接口。
Array.prototype[Symbol.iterator] = function () {
let index = 0;
let array = this;
console.log('Use iterator');
return {
next() {
return index ? { 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(arr[i]); // 打印出 1, 2。
}
arr.forEach(d => {
console.log(d); // 打印出 1, 2。
});

对象没有默许的遍历器接口
为何对象没有默许的遍历器接口?这要从两方面申明。一为遍历器是种线性处置惩罚构造,关于任何非线性的数据构造,布置了遍历器接口,就等于布置一种线性转换。二是对象原本就是一个无序的鸠合,假如愿望其有序,能够运用Map替代。这等于各有其长,各安其职。屎壳郎假如不滚粪球而去采蜜,那,呃,花mm能够就遭殃咯。

自行天生的类数组对象(具有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()

延长浏览

关于ES6的Symbol:链接。


推荐阅读
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • javascript  – 概述在Firefox上无法正常工作
    我试图提出一些自定义大纲,以达到一些Web可访问性建议.但我不能用Firefox制作.这就是它在Chrome上的外观:而那个图标实际上是一个锚点.在Firefox上,它只概述了整个 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文介绍了获取关联数组键的列表的方法,即使用Object.keys()函数。同时还提到了该方法在不同浏览器的支持情况,并附上了一个代码片段供读者参考。 ... [详细]
  • 解决.net项目中未注册“microsoft.ACE.oledb.12.0”提供程序的方法
    在开发.net项目中,通过microsoft.ACE.oledb读取excel文件信息时,报错“未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序”。本文提供了解决这个问题的方法,包括错误描述和代码示例。通过注册提供程序和修改连接字符串,可以成功读取excel文件信息。 ... [详细]
  • 本文介绍了一种在PHP中对二维数组根据某个字段进行排序的方法,以年龄字段为例,按照倒序的方式进行排序,并给出了具体的代码实现。 ... [详细]
  • 本文介绍了如何对PHP二维数组进行排序以及如何获取最大值。同时还提到了在数据分析系统中使用排序的实例,以及如何统计角色等级和创建角色总数。 ... [详细]
  • 简述在某个项目中需要分析PHP代码,分离出对应的函数调用(以及源代码对应的位置)。虽然这使用正则也可以实现,但无论从效率还是代码复杂度方面考虑ÿ ... [详细]
  • 本文详细介绍了PHP中与URL处理相关的三个函数:http_build_query、parse_str和查询字符串的解析。通过示例和语法说明,讲解了这些函数的使用方法和作用,帮助读者更好地理解和应用。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • Hibernate延迟加载深入分析-集合属性的延迟加载策略
    本文深入分析了Hibernate延迟加载的机制,特别是集合属性的延迟加载策略。通过延迟加载,可以降低系统的内存开销,提高Hibernate的运行性能。对于集合属性,推荐使用延迟加载策略,即在系统需要使用集合属性时才从数据库装载关联的数据,避免一次加载所有集合属性导致性能下降。 ... [详细]
  • 本文讨论了在使用PHP cURL发送POST请求时,请求体在node.js中没有定义的问题。作者尝试了多种解决方案,但仍然无法解决该问题。同时提供了当前PHP代码示例。 ... [详细]
  • php缓存ri,浅析ThinkPHP缓存之快速缓存(F方法)和动态缓存(S方法)(日常整理)
    thinkPHP的F方法只能用于缓存简单数据类型,不支持有效期和缓存对象。S()缓存方法支持有效期,又称动态缓存方法。本文是小编日常整理有关thinkp ... [详细]
author-avatar
半邪书生66_516
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有