JavaScript – Iterator
参考
前言
es6 以后经常可以看到 for...of 的踪迹. 如果你细看会发现它挺神奇的. 不只是 Array 可以被 for...of, 有些对象也可以被 for...of.
const array = [1, 2, 3];
console.log(Array.isArray(array)); // true
for (const value of array) {
console.log(value); // 1, 2, 3
}
上面 Array 能被 for...of
下面 isArray 是 false, querySelectorAll 返回的是一个 NodeListOf 对象. 但是依然可以被 for...of.
const notArray = document.querySelectorAll('h1');
console.log(Array.isArray(notArray)); // false
for (const value of notArray) {
console.log(value); // h1
}
其原因是, 只要是 Iterable 对象就可以被 for...of 遍历. 而 Array 和 NodeListOf 都属于 Iterable 对象, 所以它们都可以被遍历.
Iterable 对象
这是 TypeScript 对 Iterable 对象的描述
interface Iterable<T> {
[Symbol.Iterator](): Iterator<T>;
}
一个对象里有一个 Symbol.Iterator 方法, 就是一个 Iterable 对象. 之前在 JavaScript – Symbol 里, 我有提到了 es6 如何利用各种 build-in Symbol 来做许多事情, 其中一个就是 Iterator 了.
不只 JS, C# 也是有 Iterator 的概念. List<string> 的 List 就是一个 Iterable 对象来的, 所以它支持 foreach.
Iterator
Iterable 对象的 Symbol.Iterator 方法必须返回一个 iterator.

这个 Iterator 也是一个对象, 它有一个最重要的方法 next, 下面我们来看看 Iterator 对象怎么用.
How to use a Iterator
const Iterator: Iterator<string> = {
next() {
return { value: '1', done: true };
},
};
const { value, done } = iterator.next();
console.log(value); // '1'
console.log(done); // true
虽然我用 TypeScript 写, 但是你可以把它当 JavaScript 看, 去掉你看不懂的地方就可以了. 不影响理解的.
next 方法返回一个 value 和一个 boolean done 表示遍历是否完结了.
站在一个使用 Iterator 的角度, 我们可以了解到.
1. Iterator 是对象, 有一个 next 方法
2. 调用 next 可以拿到一个值, 同时可以知道是否遍历结束. 如果还没有结束意味着可以继续 next 拿到下一个值.
3. Iterator 内部如何实现遍历, 调用者是不知道的, 可能内部是一个 array 或者是一个 formula. 消费者不知道, 也不需要知道. 只要 call next 就对了.
for...of
了解了如何使用 Iterator, 就能理解 for...of 的运作逻辑了.
它只是封装了调用 .next 和判断 done 是否结束.
看看这个例子
const stringList: Iterable<string> & { value: string } = {
value: 'Derrick',
[Symbol.Iterator]() {
let index = 0;
return {
next: () => ({
value: this.value[index++],
done: index === this.value.length + 1,
}),
};
},
};
for (const value of stringList) {
console.log('value', value); // d e r r i c k
}
stringList.value = 'super';
for (const value of stringList) {
console.log('value', value); // s u p e r
}
stringList 是一个 Iterable, 一个拥有 Symbol.Iterator 方法的对象
Symbol.Iterator 返回一个 Iterator, 一个拥有 next 方法的对象. next 返回一个值和 done (表示是否遍历结束)
for...of 开始时, 会调用 Symbol.Iterator 方法得到 stringList 的 Iterator
接着调用 next 获取值放入 value, 这时 console 就会发出每一个 char 值. 这个逻辑写在 Iterator 内. for...of 并不知道 value 的由来, 它只是消费.
当 for...of 发现 done = true 时, 遍历就结束了.
Break and Return
在 for..of 内使用 break 会中断遍历, Iterator 的 return 方法会被调用.

Iterator 除了 next 方法, 还可以实现 return 和 throw 方法. throw 是配合 Generator 函数才会用到, 这篇先不提.
return 的用意是, 当调用者中断遍历时通知 iterator. 为了让 Iterator 内部做一些释放内存之类的事情.
所以一般的流程是 Iterable[Symbol.Iterator]() 获得 Iterator, 然后 .next 一直到结束
中断的情况则是调用了 next, 但在还没有 done 之前调用了 return.
for...of 内的 break 语句就会调用 iterator.return (注意: 只有 break 才是中断遍历, continue 并不是哦)
注: iterator.return 是可以传参数和返回值的, 但这个用于 Generator 函数. 一般 for...of 遍历不需要.
const stringList: Iterable<string> & { value: string } = {
value: 'Derrick',
[Symbol.Iterator]() {
let index = 0;
return {
next: () => ({
value: this.value[index++],
done: index === this.value.length + 1,
}),
return: (value) => {
console.log('return', value);
return {
value: '',
done: true,
};
},
};
},
};
for (const value of stringList) {
if (value === 'i') {
console.log('calling break');
break;
}
console.log('value', value); // d e r r i calling break return
}
Iterable + Spread Operator
Iterable > Iterator > next > values
这样步骤太多了, 有一个非常快捷的方法可以把所以 values 遍历放入 Array 中.
那就是配上 Spread Operator
const values = [...stringList]; // ['D', 'e', 'r', 'r', 'i', 'c', 'k']
JavaScript – Iterator的更多相关文章
- Javascript Iterator
[Javascript Iterator] 1.@@iterator Whenever an object needs to be iterated (such as at the beginning ...
- javascript里面支持el表达式和<s:iterator>
javascript不支持jstl标签,支持<s:iterator>和el表达式
- JavaScript 設計模型 - Iterator
Iterator Pattern是一個很重要也很簡單的Pattern:迭代器!我們可以提供一個統一入口的迭代器,Client只需要知道有哪些方法,或是有哪些Concrete Iterator,並不需要 ...
- javascript设计模式-迭代器模式(Iterator)
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 【前端】【javascript】es6中的遍历器接口Iterator
好久没发文章啦-.-为了证明我还活着,我决定从笔记里面抓一篇还算不乱比较像文章的发出来... 这些笔记是我在学es6的时候断断续续记录的,最近会一份一份整理陆陆续续发出来,顺便也自己再看一遍.我学习e ...
- [Javascript] Creating an Iterator from an Array
Every Array has a function which you can use to create an iterator. This function can only be access ...
- JavaScript 对象部署 Iterator 接口
const name = { first:"hello", last:"world", fullname: "hello world" } ...
- 《你不知道的JavaScript》整理(三)——对象
一.语法 两种形式定义:文字形式和构造形式. //文字形式 var myObj = { key: value }; //构造形式 var myObj = new Object(); myObj.key ...
- 【转】浅谈JavaScript、ES5、ES6
什么是JavaScript JavaScript一种动态类型.弱类型.基于原型的客户端脚本语言,用来给HTML网页增加动态功能.(好吧,概念什么最讨厌了) 动态: 在运行时确定数据类型.变量使用之前不 ...
- 用vue.js学习es6(六):Iterator和for...of循环
一.Iterator (遍历器)的概念: 遍历器(Iterator)就是这样一种机制.它是一种接口,为各种不同的数据结构提供统一的访问机制.任何数据结构只 要部署Iterator接口,就可以完成遍历操 ...
随机推荐
- 解决方案 | 笔记本电脑能连上WIFI,但是无Internet显示地球图标,怎么回事?(win10)
一.背景 任务栏托盘区显示地球图标,但是实际上可以上网. 疑难诊断一般是这种情况: 二.可能的有效解决方案 0 方案0:使用360断网急救箱傻瓜式修复 个人制作 | 360断网急救箱新版-2.0版单文 ...
- thinkphp模型hasOne、hasMany、belongsTo详解
在ThinkPHP框架中,hasOne.hasMany和belongsTo是用于定义模型间一对多(1:n).一对一(1:1)和多对一(n:1)关联关系的方法.以下是一些简单的示例来解释这些关系: 1. ...
- Vue查询传参
通过修改 getWK005 函数来实现这一点.这里的 query 参数就是发送 GET 请求时的查询参数.你可以将需要的条件作为 query 对象的属性传递进去.比如,如果你想要按照特定的条件查询信息 ...
- 音频文件降噪及python示例
操作系统 :Windows 10_x64 Python版本:3.9.2 noisereduce版本:3.0.2 从事音频相关工作,大概率会碰到降噪问题,今天整理下之前学习音频文件降噪的笔记,并提供Au ...
- SpringBoot2.7 霸王硬上弓 Logback1.3 → 不甜但解渴
开心一刻 一大早,她就发消息质问我 她:你给我老实交代,昨晚去哪鬼混了? 我:没有,就哥几个喝了点酒 她:那我给你打了那么多视频,为什么不接? 我:不太方便呀 她:我不信,和你哥们儿喝酒有啥不方便接视 ...
- 对比python学julia(第三章:游戏编程)--(第一节)初识游戏库(3)
1.1. 键盘和鼠标控制 在游戏应用程序中,通常使用键盘和鼠标作为游戏的操作设备.游戏的窗口都能接收来自键盘和鼠标设备的输人.当用户在键盘上按下按建或释放按键时,会产生相应的键盘事件:当用户移动 ...
- 对比python学julia(第一章)--(第六节)数字黑洞
6.1. 问题描述 6174数字黑洞是印度数学家卡普雷卡尔于1949年发现的,又称为卡普雷卡尔黑洞,其规则描述如下. 任意取一个4位的整数(4个数字不能完全相同),把4个数字由大到小排列成一个大的数, ...
- 4、Git之分支操作
4.1.分支的概述 在版本控制过程中,当需要同时推进多个任务时,可以为每个任务创建的单独分支. 虽然分支的底层实现是指针的引用,但是初学阶段可以将分支简单理解为副本,一个分支就是一个单独的副本. 使用 ...
- 【微信小程序】 全局数据共享
1.什么是全局数据共享 全局数据共享(又叫做:状态管理)是为了解决组件之间数据共享的问题. 开发中常用的全局数据共享方案有: Vuex.Redux. MobX等. 2.小程序中的全局数据共享方案 在小 ...
- 【WSDL】03 使用注解自定义服务信息
对原来的自定义WebService设置注解: package cn.cloud9.jax_ws.server.intf; import javax.jws.WebMethod; import java ...