# 揭开迭代器神秘的面纱

# 课程目标

  • 理解为什么需要迭代器?
  • 了解迭代协议,以及如何使用迭代器,编写迭代器。
  • 学会给不可迭代对象编写迭代器,让它也变成可迭代对象

# 阅读

为什么需要迭代器

在 ECMAScript较早的版本中,执行迭代必须使用循环或者其他辅助结构,随着代码增加,代码变得混乱难以理解。很多语言通过原生语言结构解决了这个问题,开发者无须实现知道如何迭代就能实现迭代操作。这个解决方案就是迭代器模式,迭代器的主要目标是消除循环的复杂性和容易出错的性质。

接下来我们来看看各个 JavaScript 中各个迭代机制的不足之处

迭代协议

在实现迭代器之前,我们需要学习迭代协议,迭代协议是可迭代对象在实现接口时需要遵循的一组规则。

自定义迭代器

学习了迭代协议,我们就可以编写属于自己的迭代器

# 任务一

请你练习显示地调用迭代器,给你一个对象数组 foodList 数据。

实现点击 下一种食物,就调用迭代器的 next () 方法 ,得到食物名称和图片,将图片显示在 类名为 foodContainer 的 p 标签中

    <button>下一种食物</button>
    <p class="foodContainer"></p>

    let foodList = [
        {chocolate:'🍫'},
        {iceCream:'🍦'},
        {popCorn:'🍿'},
        {cheese:'🧀'},
        {hamburger:'🍔'},
        {frenchFries:'🍟'},
        {apple:'🍎'},
        {sussi:'🍱'},
    ]

    // your code here

# 任务二

  1. 首先,封装一个函数 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();
    }

# 自测问题

  1. 什么是可迭代对象,什么是不可迭代对象?
  2. forEach()方法可以用于对象吗?
  3. 请问下面会在控制台输出什么?
  4. 实现迭代有哪些方式?其优、缺点分别是什么?默认迭代器必须使用什么属性作为键?
  5. 如何检测数据类型是否实现了迭代器工厂函数?调用这个工厂函数会生成什么?
  6. 迭代器 API 调用哪个方法遍历数据?其返回值是什么?同一个可迭代对象的不同迭代器实例之间有联系么?
  7. 迭代器真正维护的是什么?其对垃圾回收程序有什么影响?可迭代对象在迭代期间被修改,迭代器受影响么?
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())
  1. 请问下面会在控制台输出什么?
    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());
  1. 请问迭代器关闭后,下一次继续迭代会沿着上一次关闭的位置继续迭代,还是重新开始呢?思考下面的代码将输出什么
    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)
    }
  1. 如何指定迭代器提前关闭时执行的逻辑?哪些情况下迭代器会提前终止?
  2. 不可关闭的迭代器能否变成可关闭的?请用代码证实

# 相关参考