资讯专栏INFORMATION COLUMN

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

王军 / 1148人阅读

摘要:什么是迭代器中创建迭代器如下所示什么是生成器生成器是一种返回迭代器的函数每当招待完一条语句后函数就会自动停止执行关键字可返回任何值或表达式关键字只可在生成器内部使用,在其它地方使用会导致程序抛出语法错误所以下面例子是有错误的可迭代对象具有属

什么是迭代器

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个对象都内建了以下三种迭代器

keys

values

entries

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

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

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")
})

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85083.html

相关文章

  • 深入理解ES6迭代器与成器

    摘要:什么是迭代器中创建迭代器如下所示什么是生成器生成器是一种返回迭代器的函数每当招待完一条语句后函数就会自动停止执行关键字可返回任何值或表达式关键字只可在生成器内部使用,在其它地方使用会导致程序抛出语法错误所以下面例子是有错误的可迭代对象具有属 什么是迭代器 ES5中创建迭代器如下所示: function createIterator(items) { var i = 0 retu...

    myshell 评论0 收藏0
  • ES6迭代器与迭代对象

    摘要:通过生成器创建的迭代器也是可迭代对象,因为生成器默认会为属性赋值。我们可以用来访问对象的默认迭代器,例如对于一个数组获得了数组这个可迭代对象的默认迭代器,并操作它遍历了数组中的元素。 ES6 新的数组方法、集合、for-of 循环、展开运算符(...)甚至异步编程都依赖于迭代器(Iterator )实现。本文会详解 ES6 的迭代器与生成器,并进一步挖掘可迭代对象的内部原理与使用方法 ...

    terasum 评论0 收藏0
  • ES6】更易于继承的类语法

    摘要:的类使用熟悉的关键字指定类继承的函数,并且可以通过方法访问父类的构造函数。例如继承一个的类继承了,术语上称为基类,为派生类。例如注意到上例中,不仅是派生类的实例,也是派生类的实例,内建对象继承的实用之处是改变返回对象的类型。 和其它面向对象编程语言一样,ES6 正式定义了 class 类以及 extend 继承语法糖,并且支持静态、派生、抽象、迭代、单例等,而且根据 ES6 的新特性衍...

    Lionad-Morotar 评论0 收藏0
  • 数据结构 - 收藏集 - 掘金

    面试旧敌之红黑树(直白介绍深入理解) - Android - 掘金 读完本文你将了解到: 什么是红黑树 黑色高度 红黑树的 5 个特性 红黑树的左旋右旋 指定节点 x 的左旋 右图转成左图 指定节点 y 的右旋左图转成右图 红黑树的平衡插入 二叉查找树的插入 插入后调整红黑树结构 调整思想 插入染红后... java 多线程同步以及线程间通信详解 & 消费者生产者模式 & 死锁 & Thread...

    leeon 评论0 收藏0

发表评论

0条评论

王军

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<