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 ...
随机推荐
- MySQL ENGINES 引擎
引擎 存储引擎是数据库底层软件组织. 数据库管理系统(DBMS)使用数据引擎进行创建.查询.更新和删除数据. 不同的存储引擎提供不同的存储机制.索引技巧.锁定水平等功能. MySQL的核心就是存储引擎 ...
- Java(19)接口知识及综合案例
作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201629.html 博客主页:https://www.cnblogs.com/testero ...
- Google Style Guides
Google Style Guides Google Style Guides Google 开源项目风格指南 (zh-google-styleguide.readthedocs.io)
- js判断移动端浏览器类型,微信浏览器、支付宝小程序、微信小程序等
起因 现在市场上各种跨平台开发方案百家争鸣各有千秋,个人认为最成熟的还是hybird方案,简单的说就是写H5各种嵌入,当然作为前端工程师最希望的也就是公司采用hybird方案当作技术路线. 所谓的hy ...
- Servlet学习一(Servlet的使用流程)
一.servlet运行流程 运行流程:浏览器发送请求到服务器,服务器根据url地址在webapps中寻找对应的项目文件夹然后再web.xml中检索对应的servlet,并进行调用二.servlet类写 ...
- js基础学习之"=="与"==="的区别
var a = 1; var b = 1; var c = "1"; 1. "==" 可理解为相等运算符.相等运算符比较时,会自己进行类型转换,等于什么类型就会 ...
- c++中virtual 虚函数
转载: https://www.cnblogs.com/weiyouqing/p/7544988.html 在面向对象的C++语言中,虚函数(virtual function)是一个非常重要的概念. ...
- 确定两串乱序同构 牛客网 程序员面试金典 C++ Python
确定两串乱序同构 牛客网 程序员面试金典 C++ Python 题目描述 给定两个字符串,请编写程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串.这里规定大小写为不同字符,且考虑字符串中 ...
- 记一次 .NET 某风控管理系统 内存泄漏分析
一:背景 1. 讲故事 上个月中旬,星球里的一位朋友在微信找我,说他的程序跑着跑着内存会不断的缓慢增长并无法释放,寻求如何解决 ? 得,看样子星球还得好好弄!!! 不管怎么说,先上 windbg 说话 ...
- 如何反编译微信小程序👻
如何反编译微信小程序 准备工具: 夜神模拟器(或者你可以自己准备一个安卓模拟器,有root权限.) RE文件管理器(下载地址:https://soft.ucbug.com/uploads/shouji ...
