ES6可迭代对象与迭代器的理解

一、本文解决的问题

ES6中新增了一个语法for...of语句,可能很多前端工程师只是看到文档或者博客上都有介绍,它可以用来遍历数组、字符串、Set集合、Map等,但是对其中原理不太清楚。本文章就是来答疑解惑的。

二、可迭代对象

如果学过python就知道,python中有可迭代对象及迭代器之分

  • 1、可迭代对象有

    • 1.Array
    • 2.String
    • 3.Map
    • 4.Set
    • 5.arguments
    • 6.NodeList
  • 2、判断一个数据是否具有可迭代能力,只有当数据具有Symbol.iterator属性的时候才可以使用for...of进行迭代

    console.log(Array.prototype.hasOwnProperty(Symbol.iterator));
    console.log(Set.prototype.hasOwnProperty(Symbol.iterator));
    复制代码
  • 3、在浏览器控制台打印信息(举例一个数组的)

  • 4、从上图看出Array.prototype[Symbol.iterator]是一个函数,使用typeof判断数据类型(如果不可迭代的返回是undefined)

    console.log(typeof [][Symbol.iterator]);
    console.log(typeof {}[Symbol.iterator]);
    console.log(typeof new Set()[Symbol.iterator]);
    console.log(typeof ''[Symbol.iterator]);
    复制代码

三、手动模拟一个迭代器

  • 1、迭代器的方法

    const createIterator = items => {
      const keys = Object.keys(items);
      const len = keys.length;
      let pointer = 0; // 当前的指针位置
      return {
        next() {
          const done = pointer >= len;
          const value = !done ? items[keys[pointer++]] : undefined; // 如果当前指针位置小于总长度
          return {
            value,
            done
          }
        }
      }
    }
    复制代码
  • 2、测试数组

    const iterator1 = createIterator([1,2,3,4]);
    console.log(iterator1.next());
    console.log(iterator1.next());
    console.log(iterator1.next());
    console.log(iterator1.next());
    console.log(iterator1.next());
    复制代码
  • 3、测试对象

    const iterator2 = createIterator({a: 'a', b: 'b', c: 'c'})
    console.log(iterator2.next());
    console.log(iterator2.next());
    console.log(iterator2.next());
    console.log(iterator2.next());
    console.log(iterator2.next());
    复制代码

四、既然数组等具有可迭代的能力,但是我们直接使用数组.next()会报错的(用python中的说法,可迭代不代表是一个迭代器,只有迭代器才具有next()方法)

  • 1、错误信息

  • 2、通过上面方式判断已经具有可迭代能力的数据,如果要使用next函数,必须先将可迭代对象转成换迭代器。

  • 3、可迭代对象不一定是迭代器,但是迭代器一定是可迭代对象

五、将不可迭代的数据转换可迭代数据

  • 1、尝试在对象使用for..of

  • 2、直接修改对象原型属性

    注意一般我们开发中不会直接串改原型,方法将在另外一篇文章分享

    Object.prototype[Symbol.iterator] = function() {
      const self = this;
      const keys = Object.keys(self);
      const len = keys.length;
      let pointer = 0;
      return {
        next() {
          const done = pointer >= len;
          const value = !done ? self[keys[pointer++]]: undefined;
          return {
            done,
            value
          }
        }
      }
    }
    let obj = {name: '哈哈', gender: '男'};
    let objItem = obj[Symbol.iterator]();
    console.log('===', objItem.next());
    for (const item of obj) {
      console.log(item)
    }
    复制代码
  • 3、一般直接修改对象本身

    obj1[Symbol.iterator] = function () {
        const self = this;
        const keys = Object.keys(self);
        const len = keys.length;
        let pointer = 0;
        return {
            next() {
                const done = pointer >= len;
                const value = !done ? self[keys[pointer++]] : undefined;
                return {
                    done,
                    value
                }
            }
        }
    }
    复制代码

六、关于Generator函数的介绍

  • 1、普通函数只能返回一个值

  • 2、Generator函数可以返回多个值,也可以接受外界传递的值

  • 3、generator函数

    function * generator1() {
      console.log('开始')
      yield 1;
      yield 2;
      yield 3;
      console.log('结束')
    }
    const iterator3 = generator1();
    console.log(typeof iterator3[Symbol.iterator]);
    console.log(iterator3.next())
    for (let item of iterator3) {
    	console.log(item);
    }
    复制代码

七、关于genertaor函数传递参数的理解

注意点:只要调用一次next()不管里面是否有参数都会yield一次

  • 1、具体代码

    function * generator1() {
      console.log('开始')
      let aa = yield 1;
      console.log('aa==>', aa);
      let bb = yield aa + 2;
      console.log('bb==>', bb);
      yield 3;
      console.log('结束')
    }
    const iterator3 = generator1();
    console.log(iterator3.next()); // ①
    console.log(iterator3.next(2)); // ②
    console.log(iterator3.next(10)); // ③
    console.log(iterator3.next()); // ④
    复制代码
  • 2、上面具体实现步骤(以调用的步骤为例)

    • 1.使用步骤的时候,generator函数挂起到yield 1
    • 2.使用步骤的时候,发送的值直接赋值给aa,同时是next()函数会进行下一个yield aa + 2,当时也仅仅是挂起到yield aa + 2
    • 3.使用的时候和上面一样的
  • 3、运行结果

    开始
    { value: 1, done: false }
    aa==> 2
    { value: 4, done: false }
    bb==> 10
    { value: 3, done: false }
    结束
    { value: undefined, done: true }
    复制代码

你可能感兴趣的:(ES6可迭代对象与迭代器的理解)