js--迭代器总结
前言
正文
1 、迭代器的产生、定义和模拟
(1) for 循环的弊端
普通的for循环的弊端因为数组有已知的长度,且数组每一项都可以通过索引获取,所以整个数组可以通过递增索引来遍历。由于如下原因,通过这种循环来执行例程并不理想。
a、 迭代之前需要事先知道如何使用数据结构。数组中的每一项都只能先通过引用取得数组对象,然后再通过 [] 操作符取得特定索引位置上的项。这种情况并不适用于所有数据结构。
b、 遍历顺序并不是数据结构固有的。通过递增索引来访问数据是特定于数组类型的方式,并不适用于其他具有隐式顺序的数据结构。
(2) 迭代器的产生
迭代器是被设计专用于迭代的对象,带有特定的接口,迭代器持有一个指向集合位置的内部指针,每当调用了next()方法,迭代器就会返回一个结果 IteratorResult 对象,该结果对象有两个属性,对应下一个值的 value 以及一个布尔类型的 done,在最后一个值再调用next()则返回 done 属性值为 true(标识没有更多值供使用),并且value属性会是迭代器自身的返回值. 该返回值不是原始数据集的一部分,却成为相关数据的最后一部分,或在迭代器未提供返回值的时候使用undefined ,迭代器的自身返回值类似于函数的返回值,是向调用者返回信息的最后手段。
(3) 迭代器的模拟
根据上面的定义,手动实现迭代器函数
// createIterator 函数返回一个带有next()方法的对象,作为迭代器,每次调用next()方法,返回具体的IteratorResult 对象值
function createIterator(items) {
var i = 0;
return {
next() {
var done = (i >= items.length);
var value = !done ? items[i++] : undefined;
return {
done, value
}
}
}
}
var iterator = createIterator([11, 22, 33])
console.log(iterator.next());//{done: false, value: 11}
console.log(iterator.next());//{done: false, value: 22}
console.log(iterator.next());//{done: false, value: 33}
console.log(iterator.next());//{done: true, value: undefined}
2、 迭代器模式和可迭代对象
迭代器模式(特别是在 ECMAScript 这个语境下)描述了一个方案,即可以把有些结构称为“可迭代对象”(iterable),因为它们实现了正式的 Iterable 接口,而且可以通过迭代器 Iterator 消费。
(1)访问默认迭代器 symbol.iterator
let values = [1, 2, 3, 4]
let iterator = values[Symbol.iterator]()
console.log(iterator.next());//{value:1,deno:false}
console.log(iterator.next());//{value:2,deno:false}
console.log(iterator.next());//{value:3,deno:false}
console.log(iterator.next());//{value:4,deno:false}
console.log(iterator.next());//{value:undefiend,deno:true}
(2) 检测一个对象是否可以用来迭代
let num = 1;
let obj = {};
// 这两种类型没有实现迭代器工厂函数
console.log(num[Symbol.iterator]); // undefined
console.log(obj[Symbol.iterator]); // undefined let str = 'abc';
let arr = ['a', 'b', 'c'];
let map = new Map().set('a', 1).set('b', 2).set('c', 3);
let set = new Set().add('a').add('b').add('c');
let els = document.querySelectorAll('div');
// 这些类型都实现了迭代器工厂函数
console.log(str[Symbol.iterator]); // f values() { [native code] }
console.log(arr[Symbol.iterator]); // f values() { [native code] }
console.log(map[Symbol.iterator]); // f values() { [native code] }
console.log(set[Symbol.iterator]); // f values() { [native code] }
console.log(els[Symbol.iterator]); // f values() { [native code] }
// 调用这个工厂函数会生成一个迭代器
console.log(str[Symbol.iterator]()); // StringIterator {}
console.log(arr[Symbol.iterator]()); // ArrayIterator {}
console.log(map[Symbol.iterator]()); // MapIterator {}
console.log(set[Symbol.iterator]()); // SetIterator {}
console.log(els[Symbol.iterator]()); // ArrayIterator {}
总结:检测一个对象是否可以用来迭代的方式:typeof object[Symbol.iterator] === "function",同时可以得出很多内置类型都实现了 Iterable 接口:字符串、 数组、映射、集合、arguments 对象、NodeList 等 DOM 集合类型等。
注意:
a、 每个迭代器都表示对可迭代对象的一次性有序遍历。不同迭代器的实例相互之间没有联系,只会独立地遍历可迭代对象。
b、迭代器并不与可迭代对象某个时刻的快照绑定,而仅仅是使用游标来记录遍历可迭代对象的历程。如果可迭代对象在迭代期间被修改了,那么迭代器也会反映相应的变化。如下:
let arr = ['foo', 'baz'];
let iter = arr[Symbol.iterator]();
let iter2 = arr[Symbol.iterator]();
console.log(iter.next()); // { done: false, value: 'foo' }
console.log(iter2.next()); // { done: false, value: 'foo' }
// 在数组中间插入值
arr.splice(1, 0, 'bar');
console.log(iter.next()); // { done: false, value: 'bar' }
console.log(iter.next()); // { done: false, value: 'baz' }
console.log(iter.next()); // { done: true, value: undefined }
3 、开发中使用的迭代器
(1) 集合的内置迭代器
/*
entries()迭代器会在每次next()被调用时返回一个双项数组,此数组代表了集合中每个元素的键与值,
对于数组来说,第一项是数值索引,
对于set,第一项也是值,因为它的值也会被视为键,
对于map来说,第一项就是键
*/
let arr = [1, 2, 3]
console.log(arr.entries());//Array Iterator []
for (const item of arr.entries()) {
console.log(item);
}// [0:1],[1:2],[2:3] let set = new Set([1, 2, 3])
console.log(set.entries());//SetIterator {[1=>1],[2=>2],[3=>3]}
for (const item of set.entries()) {
console.log(item);
}// [1:1],[2:2],[3:3] let map = new Map()
map.set("first", "firseetValue")
map.set("second", "seondValue")
map.set("third", "thirdValue")
console.log(map.entries());//MapIterator {["first"=>"firseetValue"],["second"=>"seondValue"],["third"=>"thirdValue"]}
for (const item of map.entries()) {
console.log(item);
}// ["first":"firseetValue"],["second":"seondValue"],["third":"thirdValue"]
(2)字符串的迭代器
// 访问字符串中的字符可以通过下标的形式
let message = "a b"
console.log(message[0])// 'a'
let info = "a b"
for (const c of info) {
console.log(c);
}//a, ,b
4、自定义函数实现迭代器
// 与 Iterable 接口类似,任何实现 Iterator 接口的对象都可以作为迭代器使用。
class Counter {
constructor(limit) {
this.limit = limit;
}
[Symbol.iterator]() {
let count = 1,// 把计数器变量放到闭包里,然后通过闭包返回迭代器,让一个可迭代对象能够创建多个迭代器,且每创建一个迭代器就对应一个新计数器
limit = this.limit;
return {
next() {
if (count <= limit) {
return { done: false, value: count++ };
} else {
return { done: true, value: undefined };
}
},
// 可选的 return() 方法用于指定在迭代器提前关闭时执行的逻辑
return() {
console.log('Exiting early');
return { done: true };
}
};
}
}
let counter = new Counter(3);
for (let i of counter) { console.log(i); }
// 1
// 2
// 3
for (let i of counter) { console.log(i); }
// 1
// 2
// 3 let counter2 = new Counter(5);
try {
for (let i of counter2) {
if (i > 2) {
throw 'err';
}
console.log(i);
}
} catch (e) { }
// 1
// 2
// Exiting early
写在最后
以上就是本文的全部内容,希望给读者带来些许的帮助和进步,方便的话点个关注,小白的成长之路会持续更新一些工作中常见的问题和技术点。

js--迭代器总结的更多相关文章
- js 迭代器 解说
这里要说的是迭代器,是一种思路而已,代码相对来不是最关键的,个人认为,最关键的部分是实现的思路 要求: 在一个网页中,将所有的 p 元素的内容进行替换,但是在特定的位置的 p 元素是要有差异的进行替换 ...
- js迭代器模式
在迭代器模式中,通常有一个包含某种数据的集合的对象.该数据可能储存在一个复杂数据结构内部,而要提供一种简单 的方法能够访问数据结构中的每个元素. 实现如下: //迭代器模式 var agg = (fu ...
- Vue模板逻辑
前面的话 上一篇介绍了Vue的模板内容,而对于一般的模板引擎来说,除了模板内容,还包括模板逻辑.常用的模板逻辑包括条件和循环.本文将详细介绍Vue模板逻辑 条件渲染 在Vue中,实现条件逻辑依靠条件指 ...
- ch7-列表渲染(v-for key 数组更新检测 显示过滤/排序结果)
1 说明 我们用 v-for 指令根据一组数组的选项列表进行渲染. v-for 指令需要以 item in items 形式的特殊语法, items 是源数据数组并且 item 是数组元素迭代的别名. ...
- JS常用的设计模式(12)—— 迭代器模式
迭代器模式提供一种方法顺序访问一个聚合对象中各个元素,而又不需要暴露该方法中的内部表示. js中我们经常会封装一个each函数用来实现迭代器. array的迭代器: forEach = functio ...
- js数组的内部实现,迭代器,生成器和内包
js内部实现 在js以外的很多语言中,数组将会隐式占用一段连续的内存空间.这种隐式的内部实现,使得高效的内存使用及高速的元素方法称为可能,而 在javascript中,数组实体是一个对象,所以通常的实 ...
- js设计模式--迭代器模式
迭代器模式: 迭代器模式提供一种方法顺序访问一个聚合对象中各个元素,而又不需要暴露该方法中的内部表示.js中我们经常会封装一个each函数用来实现迭代器. 理解的意思:提供一个方法,去把对象的每一项按 ...
- [js高手之路] es6系列教程 - 迭代器与生成器详解
什么是迭代器? 迭代器是一种特殊对象,这种对象具有以下特点: 1,所有对象都有一个next方法 2,每次调用next方法,都会返回一个对象,该对象包含两个属性,一个是value, 表示下一个将要返回的 ...
- [js高手之路] es6系列教程 - 迭代器,生成器,for...of,entries,values,keys等详解
接着上文[js高手之路] es6系列教程 - 迭代器与生成器详解继续. 在es6中引入了一个新的循环结构for ....of, 主要是用来循环可迭代的对象,那么什么是可迭代的对象呢? 可迭代的对象一般 ...
- js设计模式——4.迭代器模式
js设计模式——4.迭代器模式 代码演示 /*js设计模式——迭代器模式*/ class Iterator { constructor(container) { this.list = contain ...
随机推荐
- 北鲲云超算如何让仿真技术、HPC和人工智能之间的深度融合?
在CAE领域,随着仿真技术在多个行业的深度应用,也带来了仿真模型日益复杂.仿真过程数据倍增.仿真计算费用昂贵等问题,降阶模型.人工智能.云计算等多种技术和仿真技术的深度融合,成为了仿真技术的重要发展趋 ...
- k8s学习笔记(1)- 简单部署springboot应用
前言:k8s全称kubernetes,k8s是为容器服务而生的一个可移植容器的编排管理工具,越来越多的公司正在拥抱k8s,并且当前k8s已经主导了云业务流程,关于更多的k8s知识,可自行学习 1.k8 ...
- 2020.5.16-ICPC Central Europe Regional Contest 2019
A. ABB #include <bits/stdc++.h> using namespace std; #define PB push_back #define ZERO (1e-10) ...
- Java(16)修饰符
作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201619.html 博客主页:https://www.cnblogs.com/testero ...
- 【UE4 C++】 外部图片读取、Texture 保存 png
蓝图版 导入外部图片 file://E:/UE___Projects_Test/MyProjectAAA/Plugins/WXimage.jpg 导出图图片 一般导出 .hdr 文件 导出 png 设 ...
- ShardingJdbc基于Zookeeper实现分布式治理
随着数据规模的不断膨胀,使用多节点集群的分布式方式逐渐成为趋势.在这种情况下,如何高效.自动化管理集群节点,实现不同节点的协同工作,配置一致性,状态一致性,高可用性,可观测性等,就成为一个重要的挑战. ...
- 第1次 Beta Scrum Meeting
本次会议为Beta阶段第1次Scrum Meeting会议 会议概要 会议时间:2021年5月29日 会议地点:「腾讯会议」线上进行 会议时长:0.5小时 会议内容简介:本次会议为Beta阶段第1次会 ...
- Spring Cloud Gateway + Jwt + Oauth2 实现网关的鉴权操作
Spring Cloud Gateway + Jwt + Oauth2 实现网关的鉴权操作 一.背景 二.需求 三.前置条件 四.项目结构 五.网关层代码的编写 1.引入jar包 2.自定义授权管理器 ...
- RabbitMQ的一些理解和笔记
在这篇博客中,简单记录一下 rabbitmq 服务器中一些基本的概念. Connection: connection 为 TCP连接,是我们的应用程序和RabbitMQ服务器真正发送和接收数据的地方. ...
- Less-5闯关失败
进行第五关的通关还是用之前的方式进行测试以及判断是什么类型的注入.通过判断我们不难发现是字符型注入.但是出了问题,我们会发现按照原来的步骤进行注入都会返回"You are in " ...
