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 ...
随机推荐
- java的加载与执行原理详解
java程序从开发到最终运行经历了什么? (31) 编译期: 第一步:在硬盘某个位置(随意),新建一个xxx.java文件 第二步:使用记事本或者其他文本编辑器例如EditPlus打开xxx.java ...
- 分布式事物SAGA
目录 概述SAGA SAGA的执行方式 存在的问题 重试机制 SAGA VS TCC 实现SAGA的框架 概述SAGA SAGA是1987 Hector & Kenneth 发表的论文,主要是 ...
- Java项目中常用的的五大设计原则
今天我们一起来聊聊关于设计原则相关的知识点. SOLID五大原则是什么 SRP 单一责任原则 单一责任原则,从名字上我们就能比较好的去理解它.这项原则主张一个对象只专注于单个方面的逻辑,强调了职责的专 ...
- XSS_Labs靶场通关
XSS-labs靶场(1-20) 开始通关! 0x01 (直接漏洞注入) 反射型xss注入 1.遇到?name=text,尝试参数注入 注入语句: <script>alert('xss ...
- kivy浮点布局
from kivy.app import App from kivy.uix.floatlayout import FloatLayout class FloatLayoutWidget(FloatL ...
- [软工顶级理解组] Beta阶段项目展示
目录 团队成员 软件介绍 项目简介 预期典型用户 功能描述 预期目标用户数 用户反馈 团队管理 分工协作 项目管理 取舍平衡 代码管理 程序测试 代码规范 文档撰写 继续开发指导性 用户沟通 需求分析 ...
- 单片机STM32的启动文件详解--学习笔记
启动文件简介 启动文件由汇编编写,是系统上电复位后第一个执行的程序.主要做了以下工作: 1.初始化堆栈指针SP=_initial_sp 2.初始化PC 指针=Reset_Handler 3.初始化中断 ...
- TensorFlow从入门到入坑(2)
TensorFlow学习(2) 一.jupyter notebook的安装和使用 1. 什么是jupyter notebook jupyter notebook(http://jupyter.org/ ...
- linux cut
参考:Linux cut 命令详解_Linux_脚本之家 (jb51.net) 参考:cut命令_Linux cut 命令用法详解:连接文件并打印到标准输出设备上 (linuxde.net)
- palindrome-partitioning-ii leetcode C++
Given a string s, partition s such that every substring of the partition is a palindrome. Return the ...