一、迭代器

JavaScript 原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6 又添加了Map和Set。这样就需要一种统一的接口机制,来处理所有不同的数据结构。遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)

1.Iterator的作用:

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

2.原生具备iterator接口的数据(可用for of遍历)

  • Array
  • set容器
  • map容器
  • String
  • 函数的 arguments 对象
  • NodeList 对象
let arr3 = [1, 2, 'kobe', true];
for(let i of arr3){
console.log(i); // 1 2 kobe true
}
let str = 'abcd';
for(let item of str){
console.log(item); // a b c d
}
function fun() {
for (let i of arguments) {
console.log(i) // 1 4 5
}
}
fun(1, 4, 5)
var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
for (var e of engines) {
console.log(e);
}
// Gecko
// Trident
// Webkit

3.迭代器的工作原理

  • 创建一个指针对象,指向数据结构的起始位置。
  • 第一次调用next方法,指针自动指向数据结构的第一个成员
  • 接下来不断调用next方法,指针会一直往后移动,直到指向最后一个成员
  • 每调用next方法返回的是一个包含value和done的对象,{value: 当前成员的值,done: 布尔值}

    • value表示当前成员的值,done对应的布尔值表示当前的数据的结构是否遍历结束。
    • 当遍历结束的时候返回的value值是undefined,done值为true

4.手写一个迭代器

    function myIterator(arr) {
let nextIndex = 0
return {
next: function() {
return nextIndex < arr.length
? { value: arr[nextIndex++], done: false }
: { value: undefined, done: true }
}
}
}
let arr = [1, 4, 'ads']// 准备一个数据
let iteratorObj = myIterator(arr)
console.log(iteratorObj.next()) // 所有的迭代器对象都拥有next()方法,会返回一个结果对象
console.log(iteratorObj.next())
console.log(iteratorObj.next())
console.log(iteratorObj.next())

5.注意点

① for of循环不支持遍历普通对象

var obj = { a: 2, b: 3 }
for (let i of obj) {
console.log(i) // Uncaught TypeError: obj is not iterable
}

对象的Symbol.iterator属性,指向该对象的默认遍历器方法。当使用for of去遍历某一个数据结构的时候,首先去找Symbol.iterator,找到了就去遍历,没有找到的话不能遍历,提示Uncaught TypeError: XXX is not iterable

② 当使用扩展运算符(...)或者对数组和 Set 结构进行解构赋值时,会默认调用Symbol.iterator方法

let arr1 = [1,3]
let arr2 = [2,3,4,5]
arr2 = [1,...arr2,6]
console.log(arr2) // [1, 2, 3, 4, 5, 6]

二、生成器

1.概念

  • Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
  • 语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态
  • Generator 函数除了状态机,还是一个遍历器对象生成函数
  • 可暂停函数(惰性求值), yield可暂停,next方法可启动。每次返回的是yield后的表达式结果

2.特点

  • function关键字与函数名之间有一个星号;
  • 函数体内部使用yield表达式,定义不同的内部状态
 function* generatorExample(){
console.log("开始执行")
yield 'hello';
yield 'generator';
}
// generatorExample()
// 这种调用方法Generator 函数并不会执行
let MG = generatorExample() // 返回指针对象
MG.next() //开始执行 {value: "hello", done: false}

Generator 函数是分段执行的,调用next方法函数内部逻辑开始执行,遇到yield表达式停止,返回{value: yield后的表达式结果/undefined, done: false/true},再次调用next方法会从上一次停止时的yield处开始,直到最后。

function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next()// { value: 'hello', done: false }
hw.next()// { value: 'world', done: false }
hw.next()// { value: 'ending', done: true }
hw.next()// { value: undefined, done: true }

第一次调用,Generator 函数开始执行,直到遇到第一个yield表达式为止。next方法返回一个对象,它的value属性就是当前yield表达式的值hello,done属性的值false,表示遍历还没有结束。

第二次调用,Generator 函数从上次yield表达式停下的地方,一直执行到下一个yield表达式。next方法返回的对象的value属性就是当前yield表达式的值world,done属性的值false,表示遍历还没有结束。

第三次调用,Generator 函数从上次yield表达式停下的地方,一直执行到return语句(如果没有return语句,就执行到函数结束)。next方法返回的对象的value属性,就是紧跟在return语句后面的表达式的值(如果没有return语句,则value属性的值为undefined),done属性的值true,表示遍历已经结束。

第四次调用,此时 Generator 函数已经运行完毕,next方法返回对象的value属性为undefined,done属性为true。以后再调用next方法,返回的都是这个值。

3.next传递参数

yield表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。

function* generatorExample () {
console.log('开始执行')
let result = yield 'hello'
console.log(result)
yield 'generator'
}
let MG = generatorExample()
MG.next()
MG.next()
// 开始执行
// undefined
// {value: "generator", done: false}

没有传值时result默认是undefined,接下来我们向第二个next传递一个参数,看下输出结果是啥?

function* generatorExample () {
console.log('开始执行')
let result = yield 'hello'
console.log(result)
yield 'generator'
}
let MG = generatorExample()
MG.next()
MG.next(11)
// 开始执行
// 11
// {value: "generator", done: false}

4.与 Iterator 接口的关系

我们上文中提到对象没有iterator接口,用for...of遍历时便会报错。

let obj = { username: 'kobe', age: 39 }
for (let i of obj) {
console.log(i) // Uncaught TypeError: obj is not iterable
}

由于 Generator 函数就是遍历器生成函数,因此可以把 Generator 赋值给对象的Symbol.iterator属性,从而使得该对象具有 Iterator 接口

let obj = { username: 'kobe', age: 39 }
obj[Symbol.iterator] = function* myTest() {
yield 1;
yield 2;
yield 3;
};
for (let i of obj) {
console.log(i) // 1 2 3
}

上面代码中,Generator函数赋值给Symbol.iterator属性,从而使得obj对象具有了 Iterator 接口,可以被for of遍历了。

5.Generator的异步的应用

业务需求:

  • 发送ajax请求获取新闻内容
  • 新闻内容获取成功后再次发送请求,获取对应的新闻评论内容
  • 新闻内容获取失败则不需要再次发送请求。

如何实现(前端核心代码如下):

    function* sendXml() {
// url为next传参进来的数据
let url = yield getNews('http://localhost:3000/news?newsId=2');//获取新闻内容
yield getNews(url);//获取对应的新闻评论内容,只有先获取新闻的数据拼凑成url,才能向后台请求
}
function getNews(url) {
$.get(url, function (data) {
console.log(data);
let commentsUrl = data.commentsUrl;
let url = 'http://localhost:3000' + commentsUrl;
// 当获取新闻内容成功,发送请求获取对应的评论内容
// 调用next传参会作为上次暂停是yield的返回值
sx.next(url);
})
}
let sx = sendXml();// 发送请求获取新闻内容
sx.next();

如果觉得文章对你有些许帮助,欢迎在我的GitHub博客点赞和关注,感激不尽!

参考文章

ECMAScript 6 入门

进阶 Javascript 生成器

ES6生成器函数generator

ES6迭代器和生成器的更多相关文章

  1. ES6 迭代器和生成器

    设计为了更高效的数据处理,避免过多for循环嵌套(代码复杂度,跟踪多个循环变量) 1. 迭代器: 为迭代过程设计的接口 所有的迭代器对象都有next()方法,每次调用都返回一个结果对象,对象有两个属性 ...

  2. ES6深入浅出-4 迭代器与生成器-3.生成器 & for...of

    迭代器平时用的很少.但是如果你是写框架的,你会经常用到迭代器. 生成器是专门用来做迭代器的东西 发布器是要产生一个叫做next的对象,如果你要产生这种对象.就可以使用ES6新出的语法. ES6的新语法 ...

  3. 掌握JavaScript中的迭代器和生成器,顺便了解一下async、await的原理

    掌握JavaScript中的迭代器和生成器,顺便了解一下async.await的原理 前言 相信很多人对迭代器和生成器都不陌生,当提到async和await的原理时,大部分人可能都知道async.aw ...

  4. Python 从零学起(纯基础) 笔记 之 迭代器、生成器和修饰器

    Python的迭代器. 生成器和修饰器 1. 迭代器是访问集合元素的一种方式,从第一个到最后,只许前进不许后退. 优点:不要求事先准备好整个迭代过程中的所有元素,仅仅在迭代到某个元素时才计算该元素,而 ...

  5. Python之模块,迭代器与生成器

    本节涉及内容: 1. 迭代器和生成器 2. 递归 3. 字符串格式化 4. 模块 内置模块 自定义模块 第三方模块 5. 序列化的模块 json pickle (一). 迭代器和生成器: 迭代器:  ...

  6. Python之迭代器和生成器

    Python 迭代器和生成器 迭代器 Python中的迭代器为类序列对象(sequence-like objects)提供了一个类序列的接口,迭代器不仅可以对序列对象(string.list.tupl ...

  7. python学习笔记四 迭代器,生成器,装饰器(基础篇)

    迭代器 __iter__方法返回一个迭代器,它是具有__next__方法的对象.在调用__next__方法时,迭代器会返回它的下一个值,若__next__方法调用迭代器 没有值返回,就会引发一个Sto ...

  8. 【Python】迭代器、生成器、yield单线程异步并发实现详解

    转自http://blog.itpub.net/29018063/viewspace-2079767 大家在学习python开发时可能经常对迭代器.生成器.yield关键字用法有所疑惑,在这篇文章将从 ...

  9. 15.python的for循环与迭代器、生成器

    在前面学习讲完while循环之后,现在终于要将for循环这个坑填上了.之所以拖到现在是因为for循环对前面讲过的序列.字典.集合都是有效的,讲完前面的内容再来讲for循环会更加容易上手. 首先,for ...

随机推荐

  1. Java设计模式七种写法

    懒汉模式-线程不安全 public class Singleton { private static Singleton instance; private Singleton (){ } publi ...

  2. O021、创建 Image

    参考https://www.cnblogs.com/CloudMan6/p/5393376.html   本节演示如何通过 Web GUI 和 CLI 两种方法创建image.   OpenStack ...

  3. TVM安装

    因为现在NNVM的代码都转移到了TVM中,NNVM代码也不再进行更新,因此选择安装的是TVM. git clone --recursive https://github.com/dmlc/tvm su ...

  4. 转载:Linux目录文件的权限查看与修改

    ########################################                                                             ...

  5. vue项目打包后在IE浏览器报错,页面显示空白

    之前写一个项目,一直放在谷歌浏览器调试测试,到尾声时放到IE浏览器结果直接白屏,页面打不开 找了网上的方法,加了babel-polyfill插件后还是不行,后来排查发现是打包插件出了问题,因为用的项目 ...

  6. dedecms 调用所属栏目的二级栏目列表

    include\taglib\channel.lib.php 在 else if($type=='self') { if($reid==0) return ''; $sql = "SELEC ...

  7. traceback:让你更加灵活地处理python的异常

    异常 异常在python中是屡见不鲜了,程序在执行到某一行代码时,发现有问题,比如数组索引越界,变量没有定义啊等等,此时就会抛出异常 捕获异常 在python,一般都是使用try···except来对 ...

  8. 月薪 30K Java 程序员,需要掌握哪些技术?

    转载自:Java3y 1-5年的Java程序员,薪资区间大致是在15-25K左右,那有没有可能提前达到30K的薪资呢?有人说这只能是大企业或者互联网企业工程师才能拿到.也许是的,小公司或者非互联网企业 ...

  9. RMQ求最值

    1. 概述 RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A ...

  10. Open Project' has encountered a problem

    用Eclipse作android开发时,打开IDE,经常有的工程目录点击后会出现下面的问题提示: 这种情况往往是工程文件夹中的.project文件丢失了,所以从别的工程复制过来,就可以用啦.