# 揭开迭代器神秘的面纱
# 课程目标
- 理解为什么需要迭代器?
- 了解迭代协议,以及如何使用迭代器,编写迭代器。
- 学会给不可迭代对象编写迭代器,让它也变成可迭代对象
# 阅读
为什么需要迭代器
在 ECMAScript较早的版本中,执行迭代必须使用循环或者其他辅助结构,随着代码增加,代码变得混乱难以理解。很多语言通过原生语言结构解决了这个问题,开发者无须实现知道如何迭代就能实现迭代操作。这个解决方案就是迭代器模式,迭代器的主要目标是消除循环的复杂性和容易出错的性质。
接下来我们来看看各个 JavaScript 中各个迭代机制的不足之处
- 不同的循环构造缺点 (opens new window)
- JavaScript 迭代器概述 (opens new window) 学习 javascript 各个迭代机制的利弊
- JavaScript Symbols、Iterators、Generators、Async/Await 和 Async Iterators——所有的解释都很简单 (opens new window)
迭代协议
在实现迭代器之前,我们需要学习迭代协议,迭代协议是可迭代对象在实现接口时需要遵循的一组规则。
自定义迭代器
学习了迭代协议,我们就可以编写属于自己的迭代器
- 迭代器 | MDN (opens new window)
- ES6迭代器的简单指南和示例 (opens new window)
- Iterable object(可迭代对象) (opens new window)
- ES6 迭代器深入 (opens new window)
- A Simple Explanation of JavaScript Iterators (opens new window)
- ES6 Iterators in Depth (opens new window)
- 迭代器 | you-dont-know-js-es6 (opens new window)
- 什么是 JavaScript 迭代器,我可以在哪里使用它们?| 30 seconds of code (opens new window)
# 任务一
请你练习显示地调用迭代器,给你一个对象数组 foodList 数据。
实现点击 下一种食物
,就调用迭代器的 next () 方法 ,得到食物名称和图片,将图片显示在 类名为 foodContainer 的 p 标签中
<button>下一种食物</button>
<p class="foodContainer"></p>
let foodList = [
{chocolate:'🍫'},
{iceCream:'🍦'},
{popCorn:'🍿'},
{cheese:'🧀'},
{hamburger:'🍔'},
{frenchFries:'🍟'},
{apple:'🍎'},
{sussi:'🍱'},
]
// your code here
# 任务二
- 首先,封装一个函数 isIterable 判断数据结构是否是可迭代对象。
/**
* @description 判断传入的数据结构 data 是否是可迭代对象
* @method isIterable
* @param data 任意数据结构
* @return {Boolean} 如果是可迭代对象返回 true,如果不是 返回 false
*/
function isIterable(data){
//your code here
}
const books = {
html:['HTML5高级程序设计','Head First HTML and CSS'],
css:['精通CSS','CSS权威指南','CSS禅意花园','响应式Web设计实践','网站重构'],
javascript:['JavaScript DOM编程艺术','JavaScript高级程序设计','高性能JavaScript','编写可维护的JavaScript','JavaScript模式'],
node:['深入浅出Node.js','了不起的Node.js: 将JavaScript进行到底','Node.js实战'],
}
//测试用例
console.log(isIterable(books) )// => false
# 任务三
接下来我们来实现讲一个不可迭代对象转换成可迭代对象。
给你一个对象数组 books 对象,经过判断您会知道他是不可迭代对象,请你实现一个自定义迭代器,实现可以通过 let...of 获取 books 对象中的所有书籍。
const books = {
html:['HTML5高级程序设计','Head First HTML and CSS'],
css:['精通CSS','CSS权威指南','CSS禅意花园','响应式Web设计实践','网站重构'],
javascript:['JavaScript DOM编程艺术','JavaScript高级程序设计','高性能JavaScript','编写可维护的JavaScript','JavaScript模式'],
node:['深入浅出Node.js','了不起的Node.js: 将JavaScript进行到底','Node.js实战'],
}
//编码实现 books 迭代器
...
//测试用例
console.log(isIterable(books) )// => true
for(let book of books){
console.log(book)
}
//HTML5高级程序设计
//Head First HTML and CSS
//精通CSS
//CSS权威指南
...
//Node.js实战
let [html_book1,html_book2] = [...books];
console.log(`第一本 html 书籍:${html_book1},第二本 html 书籍:${html_book2}`)
//第一本 html 书籍:HTML5高级程序设计,第二本 html 书籍:Head First HTML and CSS
# 任务四
编写迭代器,实现一个斐波那契数列,并且跑通下面的测试用例。
function fibonacciIterator(endIndex) {
// your code here
}
// 测试用例
let fibonacci = fibonacciIterator(7); // 生成最开始的七个数字
let result = fibonacci.next();
while (!result.done) {
console.log(result.value); // 1 1 2 3 5 8 13 21
result = fibonacci.next();
}
# 自测问题
- 什么是可迭代对象,什么是不可迭代对象?
- forEach()方法可以用于对象吗?
- 请问下面会在控制台输出什么?
- 实现迭代有哪些方式?其优、缺点分别是什么?默认迭代器必须使用什么属性作为键?
- 如何检测数据类型是否实现了迭代器工厂函数?调用这个工厂函数会生成什么?
- 迭代器 API 调用哪个方法遍历数据?其返回值是什么?同一个可迭代对象的不同迭代器实例之间有联系么?
- 迭代器真正维护的是什么?其对垃圾回收程序有什么影响?可迭代对象在迭代期间被修改,迭代器受影响么?
let arr = ['apple','banana']
let iter1 = arr[Symbol.iterator]()
let iter2 = arr[Symbol.iterator]()
console.log(iter1.next())
console.log(iter1.next())
console.log(iter2.next())
console.log(iter2.next())
- 请问下面会在控制台输出什么?
let users = ['Amy','Jackson'];
let iter = users[Symbol.iterator]();
console.log(iter.next());
users.splice(1,0,'Jennie');
console.log(iter.next());
console.log(iter.next());
- 请问迭代器关闭后,下一次继续迭代会沿着上一次关闭的位置继续迭代,还是重新开始呢?思考下面的代码将输出什么
let arr = ['STEP 1',' STEP 2','STEP 3','STEP 4']
let iter = arr[Symbol.iterator]();
for(let i of iter){
console.log(i);
if( i > 1){
break;
}
}
for(let i of iter){
console.log(i)
}
- 如何指定迭代器提前关闭时执行的逻辑?哪些情况下迭代器会提前终止?
- 不可关闭的迭代器能否变成可关闭的?请用代码证实
# 相关参考
← 足球小将 JavaScript 生成器 →