全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

深入理解ES6的迭代器与生成器

本文介绍了深入理解ES6的迭代器与生成器,分享给大家,具体如下:

循环语句的问题

var colors = ["red", "green", "blue"];
for(var i=0; i<colors.length; i++){
  console.log(colors[i]);
}

在ES6之前,这种标准的for循环,通过变量来跟踪数组的索引。如果多个循环嵌套就需要追踪多个变量,代码复杂度会大大增加,也容易产生错用循环变量的bug。

迭代器的出现旨在消除这种复杂性并减少循环中的错误。

什么是迭代器

我们先感受一下用ES5语法模拟创建一个迭代器:

function createIterator(items) {
  var i = 0;
  
  return { // 返回一个迭代器对象
    next: function() { // 迭代器对象一定有个next()方法
      var done = (i >= items.length);
      var value = !done ? items[i++] : undefined;
      
      return { // next()方法返回结果对象
        value: value,
        done: done
      };
    }
  };
}

var iterator = createIterator([1, 2, 3]);

console.log(iterator.next()); // "{ value: 1, done: false}"
console.log(iterator.next()); // "{ value: 2, done: false}"
console.log(iterator.next()); // "{ value: 3, done: false}"
console.log(iterator.next()); // "{ value: undefiend, done: true}"
// 之后所有的调用都会返回相同内容
console.log(iterator.next()); // "{ value: undefiend, done: true}"

以上,我们通过调用createIterator()函数,返回一个对象,这个对象存在一个next()方法,当next()方法被调用时,返回格式{ value: 1, done: false}的结果对象。

因此,我们可以这么定义:迭代器是一个拥有next()方法的特殊对象,每次调用next()都返回一个结果对象。

借助这个迭代器对象,我们来改造刚开始那个标准的for循环【暂时先忘记ES6的for-of循环新特性】:

var colors = ["red", "green", "blue"];
var iterator = createIterator(colors);
while(!iterator.next().done){
  console.log(iterator.next().value);
}

what?,消除循环变量而已,需要搞这么麻烦,代码上不是得不偿失了吗?

并非如此,毕竟createIterator()只需写一次,就可以一直复用。不过ES6引入了生成器对象,可以让创建迭代器的过程变得更加简单。

什么是生成器

生成器是一种返回迭代器的函数,通过function关键字后的星号(*)来表示,函数中会用到新的关键字yield。

function *createIterator(items) {
  for(let i=0; i<items.length; i++) {
    yield items[i];
  }
}

let iterator = createIterator([1, 2, 3]);

// 既然生成器返回的是迭代器,自然就可以调用迭代器的next()方法
console.log(iterator.next()); // "{ value: 1, done: false}"
console.log(iterator.next()); // "{ value: 2, done: false}"
console.log(iterator.next()); // "{ value: 3, done: false}"
console.log(iterator.next()); // "{ value: undefiend, done: true}"
// 之后所有的调用都会返回相同内容
console.log(iterator.next()); // "{ value: undefiend, done: true}"

上面,我们用ES6的生成,大大简化了迭代器的创建过程。我们给生成器函数createIterator()传入一个items数组,函数内部,for循环不断从数组中生成新的元素放入迭代器中,每遇到一个yield语句循环都会停止;每次调用迭代器的next()方法,循环便继续运行并停止在下一条yield语句处。

生成器的创建方式

生成器是个函数:

function *createIterator(items) { ... }

可以用函数表达式方式书写:

let createIterator = function *(item) { ... }

也可以添加到对象中,ES5风格对象字面量:

let o = {
  createIterator: function *(items) { ... }
};

let iterator = o.createIterator([1, 2, 3]);

ES6风格的对象方法简写方式:

let o = {
  *createIterator(items) { ... }
};

let iterator = o.createIterator([1, 2, 3]);

可迭代对象

在ES6中,所有的集合对象(数组、Set集合及Map集合)和字符串都是可迭代对象,可迭代对象都绑定了默认的迭代器。

来了来了,姗姗来迟的ES6循环新特性for-of:

var colors = ["red", "green", "blue"];
for(let color of colors){
  console.log(color);
}

for-of循环,可作用在可迭代对象上,正是利用了可迭代对象上的默认迭代器。大致过程是:for-of循环每执行一次都会调用可迭代对象的next()方法,并将迭代器返回的结果对象的value属性存储在变量中,循环将继续执行这一过程直到返回对象的done属性的值为true。

如果只需要迭代数组或集合中的值,用for-of循环代替for循环是个不错的选择。

访问默认迭代器

可迭代对象,都有一个Symbol.iterator方法,for-of循环时,通过调用colors数组的Symbol.iterator方法来获取默认迭代器的,这一过程是在JavaScript引擎背后完成的。

我们可以主动获取一下这个默认迭代器来感受一下:

let values = [1, 2, 3];
let iterator = values[Symbol.iterator]();

console.log(iterator.next()); // "{ value: 1, done: false}"
console.log(iterator.next()); // "{ value: 2, done: false}"
console.log(iterator.next()); // "{ value: 3, done: false}"
console.log(iterator.next()); // "{ value: undefined, done: true}"

在这段代码中,通过Symbol.iterator获取了数组values的默认迭代器,并用它遍历数组中的元素。在JavaScript引擎中执行for-of循环语句也是类似的处理过程。

用Symbol.iterator属性来检测对象是否为可迭代对象:

function isIterator(object) {
  return typeof object[Symbol.iterator] === "function";
}

console.log(isIterable([1, 2, 3])); // true
console.log(isIterable(new Set())); // true
console.log(isIterable(new Map())); // true
console.log(isIterable("Hello")); // true

创建可迭代对象

当我们在创建对象时,给Symbol.iterator属性添加一个生成器,则可以将其变成可迭代对象:

let collection = {
  items: [],
  *[Symbol.iterator]() { // 将生成器赋值给对象的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);
}

内建迭代器

ES6中的集合对象,数组、Set集合和Map集合,都内建了三种迭代器:

  • entries() 返回一个迭代器,其值为多个键值对。如果是数组,第一个元素是索引位置;如果是Set集合,第一个元素与第二个元素一样,都是值。
  • values() 返回一个迭代器,其值为集合的值。
  • keys() 返回一个迭代器,其值为集合中的所有键名。如果是数组,返回的是索引;如果是Set集合,返回的是值(Set的值被同时用作键和值)。

不同集合的默认迭代器

每个集合类型都有一个默认的迭代器,在for-of循环中,如果没有显式指定则使用默认的迭代器。按常规使用习惯,我们很容易猜到,数组和Set集合的默认迭代器是values(),Map集合的默认迭代器是entries()。

请看以下示例:

let colors = [ "red", "green", "blue"];
let tracking = new Set([1234, 5678, 9012]);
let data = new Map();

data.set("title", "Understanding ECMAScript 6");
data.set("format", "print");

// 与调用colors.values()方法相同
for(let value of colors) {
  console.log(value);
}

// 与调用tracking.values()方法相同
for(let num of tracking) {
  console.log(num);
}

// 与调用data.entries()方法相同
for(let entry of data) {
  console.log(entry);
}

这段代码会输入以下内容:

"red"
"green"
"blue"
1234
5678
9012
["title", "Understanding ECMAScript 6"]
["format", "print"]

for-of循环配合解构特性,操纵数据会更方便:

for(let [key, value] of data) {
  console.log(key + "=" + value);
}

展开运算符操纵可迭代对象

let set = new Set([1, 2, 3, 4, 5]),
  array = [...set];
  
console.log(array); // [1,2,3,4,5]

展开运算符可以操作所有的可迭代对象,并根据默认迭代器来选取要引用的值,从迭代器读取所有值。然后按返回顺序将它们依次插入到数组中。因此如果想将可迭代对象转换为数组,用展开运算符是最简单的方法。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# ES6  # 迭代器  # 生成器  # 迭代器与生成器  # 不得不知的ES6小技巧  # 你点的 ES6一些小技巧  # 请查收  # 浅谈让你的代码更简短  # 更整洁  # 更易读的ES6小技巧  # ES6小技巧之代替lodash  # JS实现集合的交集、补集、差集、去重运算示例【ES5与ES6写法】  # ES6 迭代器(Iterator)和 for.of循环使用方法学习(总结)  # ES6 迭代器与可迭代对象的实现  # 详谈ES6中的迭代器(Iterator)和生成器(Generator)  # 详解ES6语法之可迭代协议和迭代器协议  # ES6中的迭代器、Generator函数及Generator函数的异步操作方法  # ES6常用小技巧总结【去重、交换、合并、反转、迭代、计算等】  # 迭代  # 的是  # 多个  # 值为  # 都是  # 这一  # 是个  # 都有  # 来了  # 第一个  # 运算符  # 这段  # 我们可以  # 内建  # 就可以  # 组中  # 新特性  # 是一个  # 是在  # 是一种 


相关文章: 宝盒自助建站智能生成技巧:SEO优化与关键词设置指南  网站图片在线制作软件,怎么在图片上做链接?  已有域名和空间如何快速搭建网站?  建站之星在线版空间:自助建站+智能模板一键生成方案  完全自定义免费建站平台:主题模板在线生成一站式服务  免费制作小说封面的网站有哪些,怎么接网站批量的封面单?  建站之星安装需要哪些步骤及注意事项?  建站之星体验版:智能建站系统+响应式设计,多端适配快速建站  建站168自助建站系统:快速模板定制与SEO优化指南  建站主机SSH密钥生成步骤及常见问题解答?  网站制作模板下载什么软件,ppt模板免费下载网站?  建站之星后台密码遗忘或太弱?如何重置与强化?  如何选择适配移动端的WAP自助建站平台?  Android使用GridView实现日历的简单功能  常州自助建站费用包含哪些项目?  Python如何创建带属性的XML节点  C++如何使用std::optional?(处理可选值)  天津个人网站制作公司,天津网约车驾驶员从业资格证官网?  如何设计高效校园网站?  制作网站的过程怎么写,用凡科建站如何制作自己的网站?  ,南京靠谱的征婚网站?  建站中国必看指南:CMS建站系统+手机网站搭建核心技巧解析  电视网站制作tvbox接口,云海电视怎样自定义添加电视源?  *服务器网站为何频现安全漏洞?  如何在腾讯云服务器快速搭建个人网站?  家庭服务器如何搭建个人网站?  专业的网站制作设计是什么,如何制作一个企业网站,建设网站的基本步骤有哪些?  活动邀请函制作网站有哪些,活动邀请函文案?  湖南网站制作公司,湖南上善若水科技有限公司做什么的?  杭州银行网站设计制作流程,杭州银行怎么开通认证方式?  企业宣传片制作网站有哪些,传媒公司怎么找企业宣传片项目?  Swift开发中switch语句值绑定模式  建站之星如何一键生成手机站?  台州网站建设制作公司,浙江手机无犯罪记录证明怎么开?  洛阳网站制作公司有哪些,洛阳的招聘网站都有哪些?  如何通过.red域名打造高辨识度品牌网站?  如何选择最佳自助建站系统?快速指南解析优劣  网页设计与网站制作内容,怎样注册网站?  网站制作新手教程,新手建设一个网站需要注意些什么?  云南网站制作公司有哪些,云南最好的招聘网站是哪个?  如何快速使用云服务器搭建个人网站?  佛山企业网站制作公司有哪些,沟通100网上服务官网?  关于BootStrap modal 在IOS9中不能弹出的解决方法(IOS 9 bootstrap modal ios 9 noticework)  如何选择美橙互联多站合一建站方案?  如何用wdcp快速搭建高效网站?  美食网站链接制作教程视频,哪个教做美食的网站比较专业点?  如何在Golang中使用encoding/gob序列化对象_存储和传输数据  ,在苏州找工作,上哪个网站比较好?  建站主机是否等同于虚拟主机?  整蛊网站制作软件,手机不停的收到各种网站的验证码短信,是手机病毒还是人为恶搞?有这种手机病毒吗? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。