JavaScript之ES6新特性04

概述

        本次文章主要探讨Iterator (遍历器/迭代器)循环

Iterator 

  Iterator(遍历器)的概念

        遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。简单理解就是可以一次拿到容器对象中的数据,这样就方便我们进行后续的操作。 (Iterator(遍历器)也称迭代器)

   Iterator 的作用

        Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费 。

   Iterator 的工作原理

  1. 创建一个指针对象,指向当前数据结构的起始位置(遍历器对象本质上就是一个指针对象)。
  2. 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员。
  3. 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员。
  4. 每调用 next 方法返回一个包含 value 和 done 属性的对象 ,其中value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。 

案例: 

//声明一个数组
const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧']

//使用 for...of 遍历数组
for(let v of xiyou){
    console.log(v);
}

let iterator = xiyou[Symbol.iterator]()

//调用对象的next方法
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())

运行结果: 

JavaScript之ES6新特性04_第1张图片

 Iterator协议及使用规则

         ES6 规定,默认的 Iterator 接口部署在数据结构的 Symbol.iterator 属性,或者说,一个数据结构只要具有 Symbol.iterator 属性,就可以认为是“可遍历的”(iterable)。 Symbol.iterator 属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。至于属性名 Symbol.iterator ,它是一个表达式,返回 Symbol 对象的 iterator 属性,这是一个预定义好的、类型为 Symbol 的特殊值,所以要放在方括号内。

        ES6 的有些数据结构原生具备 Iterator 接口(比如数组),即不用任何处理,就可以被 for...of 循环遍历。原因在于,这些数据结构原生部署了Symbol.iterator 属性,另外一些数据结构没有(比如对象)。凡是部署了 Symbol.iterator 属性的数据结构,就称为部署了遍历器接口。调用这个接口,就会返回一个遍历器对象。

原生具备 Iterator 接口的数据结构如下:

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函数的 arguments 对象
  • NodeList 对象

案例: 

let arr = ['a', 'b', 'c']
let iter = arr[Symbol.iterator]()
iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }

案例解读: 

        上面代码中,变量 arr 是一个数组,原生就具有遍历器接口,部署在 arr 的 Symbol.iterator 属性上面。所以,调用这个属性,就得到遍历器对象。
        对于原生部署 Iterator 接口的数据结构,不用自己写遍历器生成函数, for...of 循环会自动遍历它们。除此之外,其他数据结构(主要是对象)的Iterator 接口,都需要自己在 Symbol.iterator 属性上面部署,这样才会被 for...of 循环遍历。

自定义遍历器(迭代器)

        对象是没有实现迭代器,所以不能遍历对象,为了可以实现对象的遍历,我们需要在对象上实现上面说的迭代器。 

案例:

//声明一个对象
const banji = {
  name: '终极一班',
  stus: ['xiaoming', 'xiaoning', 'xiaotian', 'knight'],
  [Symbol.iterator]() {
    //索引变量
    let index = 0
    //保存this指向
    let _this = this
    return {
      next: function () {
        if (index < _this.stus.length) {
          const result = { value: _this.stus[index], done: false }
          //下标自增
          index++
          //返回结果
          return result
        } else {
          return { value: undefined, done: true }
        }
      }
    }
  }
}

//遍历这个对象
for (let v of banji) {
  console.log(v)
}

 运行结果:JavaScript之ES6新特性04_第2张图片

调用 Iterator 接口的场合 

        有一些场合会默认调用 Iterator 接口(即 Symbol.iterator 方法)。

 (1)解构赋值

         对数组和 Set 结构进行解构赋值时,会默认调用 Symbol.iterator 方法。

 (2)扩展运算符

         扩展运算符(...)也会调用默认的 Iterator 接口。

 (3)其他场合(还有yield*,此处不做深究)

        由于数组的遍历会调用遍历器接口,所以任何接受数组作为参数的场合,其实都调用了遍历器接口。下面是一些例子:

  • for...of
  • Array.from()
  • Map(), Set(), WeakMap(), WeakSet()(比如 new Map([['a',1],['b',2]]) )
  • Promise.all()
  • Promise.race()

详情可点击:JavaScript中文网 - 现代 JavaScript 教程

你可能感兴趣的:(es6,前端,ecmascript)