深入理解ES6之《迭代器与生成器》

什么是迭代器

ES5中创建迭代器如下所示:

function createIterator(items) {
  var i = 0
  return {
    next: function () {
      var done = i >= items.length
      var value = !done ? items[i++] : undefined
      return {
        done: done,
        value: value
      }
    }
  }
}
var iterator = createIterator([1, 2, 3])
console.log(iterator.next())

什么是生成器

生成器是一种返回迭代器的函数
每当招待完一条yield语句后函数就会自动停止执行

function *createIterator(){
  yield 1
  yield 2
  yield 3
}
let iterator =createIterator()
console.log(iterator.next())

yield关键字可返回任何值或表达式

function* createIterator(items) {
  for (let i = 0; i < items.length; i++) {
    yield items[i]
  }
}
let iterator = createIterator([1, 2, 3])
console.log(iterator.next())

yield关键字只可在生成器内部使用,在其它地方使用会导致程序抛出语法错误
所以下面例子是有错误的

function* createIterator(items) {
  items.forEach(function (element) {
    yield itemsm + 1
  });
}
let iterator = createIterator([1, 2, 3])
console.log(iterator.next())

可迭代对象具有Symbol.iterator属性,可通过Symbol.iterator指定的函数来作用于一个附属对象的迭代器
由于生成器默认会有Symbol.iterator属性赋值,因此所有通过生成器创建的迭代器都是可迭代对象
如果将for of 语句用于不可迭代对象、null或undefined将会导致程序抛出错误

访问默认迭代器

let values = [1, 2, 3]
let iterator = values[Symbol.iterator]()
console.log(iterator.next())

检测一个对象是否为可迭代对象

function isIterable(obj) {
  return typeof obj[Symbol.iterator] === "function"
}
console.log(isIterable([1, 2, 3]))

创建可迭代对象

let collection = {
  items: [],
  *[Symbol.iterator]() {
    for (let item of this.items) {
      yield item
    }
  }
}
collection.items.push(1)
collection.items.push(2)
collection.items.push(3)

for (let x of collection) {
  console.log(x)
}

内建迭代器

数组、Map集合、Set集合,这3个对象都内建了以下三种迭代器

  1. keys

  2. values

  3. entries

每个集合对象都有一个默认的迭代器,在for of循环中,如果没有显式指定则使用默认迭代器

  1. 数组和set集合默认的迭代器是values

  2. Map集合默认的迭代器是entries

let tracking = new Set([123, 456, 789])
//与调用tracking.values方法相同
for (let num of tracking) {
  console.log(num)
}

不仅仅字符串可以用for of来迭代,NodeList也可以

let divs = document.getElementsByTagName('div')
for (let div of divs) {
  console.log(div)
}

展开运算符可作用于任何可迭代对象

let one = [1, 2, 3]
let two = [100, 101, 102]
let all = [0, ...one, ...two]
console.log(all)//[0, 1, 2, 3, 100, 101, 102]

高级迭代器

给迭代器传递参数

function* createIterator() {
  let first = yield 1
  let second = yield first + 2//4+2
  yield second + 3//5+3
}
let iterator = createIterator()
console.log(iterator.next())
console.log(iterator.next(4))
console.log(iterator.next(5))
console.log(iterator.next())

在迭代器中抛出错误

function* createIterator() {
  let first = yield 1
  let second
  try {
    second = yield first + 2
  } catch (error) {
    second = 6
  }
  yield second + 3
}
let iterator = createIterator()
console.log(iterator.next())//{value: 1, done: false}
console.log(iterator.next(4)) //{value: 6, done: false}
console.log(iterator.throw(new Error('Boom')))//{value: 9, done: false}
console.log(iterator.next())//{value: undefined, done: true}

生成器返回语句

function* createIterator() {
  yield 1
  return;
  yield 2
  yield 3
}
let iterator = createIterator()
console.log(iterator.next())//{value: 1, done: false}
console.log(iterator.next())//{value: undefined, done: true}
function* createIterator() {
  yield 1
  return 42
}
let iterator = createIterator()
console.log(iterator.next())//{value: 1, done: false}
console.log(iterator.next())//{value: 42, done: true}
console.log(iterator.next())//{value: undefined, done: true}

有一点需要注意的是展开运算符与for of循环语句会直接忽略掉通过return语句指定的任何返回值,只要done一变为true就立即停止读取其它的值

异步任务执行器

向任务执行器传递参数

function run(taskDef) {
  let task = taskDef()
  let result = task.next()
  function step() {
    if (!result.done) {
      result = task.next(result.value)
      step()
    }
  }
  step()
}
run(function* () {
  let value = yield 1
  console.log(value)
  value = yield value + 3
  console.log(value)
})

异步任务执行器

function run(taskDef) {
  //创建一个无使用限制的迭代器
  let task = taskDef()
  // 开始执行任务
  let result = task.next()
  // 循环调用next函数
  function step() {
    // 如果任务未完成则继续执行
    if (!result.done) {
      if (typeof result.value === 'function') {
        result.value(function (err, data) {
          if (err) {
            result = task.throw(err)
            return;
          }
          result = task.next(data)
          step()
        })
      } else {
        result = task.next(result.value)
        step()
      }
    }
  }
  // 开始执行迭代任务
  step()
}

let fs = require('fs')
function readFile(fileName) {
  return function (callback) {
    fs.readFile(fileName, callback)
  }
}
run(function* () {
  let contents = yield readFile('config.json')
  doSomethingWith(contents)
  console.log('hello')
})
    原文作者:angelayun
    原文地址: https://segmentfault.com/a/1190000010933953
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞