zoukankan      html  css  js  c++  java
  • javascript 之迭代器

    简介

      迭代器是一种设计模式,可在容器对象 如 链表、数组上遍历,无需关心容器对象的内存分配的实现细节。简单的理解就是可以一个一个的依次拿到其中的数据,类似一个移动的指针,但是会告诉我们什么时候结束。这样我们可以拿到数据之后可以做一些我们需要做的事情。

     js 中的迭代器是什么样子的

      在javascript 中迭代器是一个特殊对象,这个迭代器对象有一个next()方法,每次调用都返回一个对象(结果对象)。结果对象有两个属性:一个是value,表示下一个将要返回的值;另一个是done,它是一个布尔类型的值,如果已经迭代到序列中的最后一个值,则它为 true。迭代器还会保存一个内部指针,用来指向当前集合中值的位置,每调用一次next()方法,都会返回下一个可用的值,类似下面这个对象的结构。

    {
      next: function () {
            return {
                value:'',
                done: true / false
            }  
        }
    }        

    迭代协议

      随着javascript 语言的能力进一步提升,新增了一些新的数据类型 如 Map、Set、WeakMap 等,为了这些不同的数据结构,可以统一的迭代,es6 增加了迭代协议这个东西。

    迭代协议并不是新的内置实现或语法,而是协议。这些协议可以被任何遵循某些约定的对象来实现。

    迭代协议具体分为两个协议:可迭代协议和迭代器协议。

    简单的理解就是在js 中任何对象只要满足迭代协议就可以遍历

    可迭代协议

    要成为可迭代对象, 一个对象必须实现 @@iterator 方法。这意味着对象(或者它原型链上的某个对象)必须有一个键为 @@iterator 的属性,可通过常量 Symbol.iterator 访问该属性:

    简单的理解,你想让一个东西可以遍历,那么这个东西要有一个 @@iterator ,这个属性可以通过Symbol.iterator 访问

    属性

    [Symbol.iterator]

    一个无参数的函数,其返回值为一个符合迭代器协议的对象。

    迭代器协议

    迭代器协议定义了产生一系列值(无论是有限个还是无限个)的标准方式。当值为有限个时,所有的值都被迭代完毕后,则会返回一个默认返回值。

    只有实现了一个拥有以下语义(semantic)的 next() 方法,一个对象才符合迭代器协议:

    属性

    next

    一个无参数函数,返回一个应当拥有以下两个属性的对象:

    done(boolean)

    next() 方法必须返回一个对象,该对象应当有两个属性: done value如果返回了一个非对象值(比如 false undefined),则会抛出一个 异常("iterator.next() returned a non-object value")。

    迭代过程

    当一个对象需要被迭代的时候(比如被写入一个 for...of 循环时),首先,会不带参数调用它的 @@iterator 方法( 此时返回的是结构是这样的 { next: function () {}}),然后使用此方法返回的迭代器获得要迭代的值(其实就是不断的调用这个next()方法)

    迭代总结

    迭代协议可以总结为,一个东西要遍历,必须满足可迭代协议跟迭代器协议

    • 可迭代协议:这个对象必须有@@iterator,可以通过Symbol.iterator 访问
    • 迭代器协议:是一个对象,这个对象的next() 函数返回一个对象,这个对象包括两个属性,一个是value,一个是done(boolean,是否是最后一个元素,done 为 true 时 value 可省略)

    也就是说 迭代器对象本质上就是一个指针对象。通过指针对象的next(),用来移动指针。

     

    自定义迭代

    对象是没有实现迭代器,所以不能遍历对象,为了可以实现对象的遍历,我们需要在对象上实现上面说的迭代器,通常有两种写法,一种是传统的写法,这种需要自己去控制内部的状态,另外一种是利用生成器函数返回的Generator的迭代器来实现,代码如下:

    传统写法

    let obj = {
      name: 'joel',
      adress: 'gz',
      [Symbol.iterator]: () => {
         // 这里不要用this, 因为是return fn, this 会丢失
        let index = -1, atrrList = Object.keys(obj);
        const objIterator = {
          next: () => {
            let result = ''
            index++
            if (index < atrrList.length) {
              result = {
                value: atrrList[index],
                done: false
              }
            } else {
              result = {
                done: true
              }
            }
            return result
          }
        }
        return objIterator
      }
    }
    
    for (const item of obj) {
        console.log('atrrs:' + item + ',value:' + obj[item])
    }

    生成器函数写法

    // 为不可迭代的对象添加迭代器
    let obj = {
      a: 1,
      b: 2
    }
    obj[Symbol.iterator] = function* () {
      let keys = Object.keys(obj);
      //取到key值的长度
      let len = keys.length;
      //定义循环变量
      let n = 0;
      //条件判断
      while (n <= len - 1) {
          yield { k: keys[n], v: obj[keys[n]] };
          n++
      }
    }
    //返回的是个对象的key和value
    for (let { k, v } of obj) {
      console.log(k, v);
    }

    其他相关如内置可迭代对象、用于可迭代对象的语法、接受可迭代对象的内置api 等 请点击 这里

  • 相关阅读:
    常用知识点集合
    LeetCode 66 Plus One
    LeetCode 88 Merge Sorted Array
    LeetCode 27 Remove Element
    LeetCode 26 Remove Duplicates from Sorted Array
    LeetCode 448 Find All Numbers Disappeared in an Array
    LeetCode 219 Contains Duplicate II
    LeetCode 118 Pascal's Triangle
    LeetCode 119 Pascal's Triangle II
    LeetCode 1 Two Sum
  • 原文地址:https://www.cnblogs.com/longbensong/p/15217121.html
Copyright © 2011-2022 走看看