ES6迭代器(Iterator)和 for.of循环使用方法

本文主要和大家介绍了es6 迭代器(iterator)和 for.of循环使用方法学习总结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望能帮助到大家。

一、什么是迭代器?

生成器概念在Java,Python等语言中都是具备的,ES6也添加到了JavaScript中。Iterator可以使我们不需要初始化集合,以及索引的变量,而是使用迭代器对象的 next 方法,返回集合的下一项的值,偏向程序化。

迭代器是带有特殊接口的对象。含有一个next()方法,调用返回一个包含两个属性的对象,分别是value和done,value表示当前位置的值,done表示是否迭代完,当为true的时候,调用next就无效了。

ES5中遍历集合通常都是 for循环,数组还有 forEach 方法,对象就是 for-in,ES6 中又添加了 Map 和 Set,而迭代器可以统一处理所有集合数据的方法。迭代器是一个接口,只要你这个数据结构暴露了一个iterator的接口,那就可以完成迭代。ES6创造了一种新的遍历命令for…of循环,Iterator接口主要供for…of消费。

二、如何使用迭代器?

1、默认 Iterator 接口

数据结构只要部署了 Iterator 接口,我们就成这种数据结构为“可遍历”(Iterable)。ES6 规定,默认的 Iterator 接口部署在数据结构的 Symbol.iterator 属性,或者说,一个数据结构只要具有 Symbol.iterator 数据,就可以认为是“可遍历的”(iterable)。

可以供 for…of 消费的原生数据结构

Array

Map

Set

String

TypedArray(一种通用的固定长度缓冲区类型,允许读取缓冲区中的二进制数据)

函数中的 arguments 对象

NodeList 对象

可以看上面的原生数据结构中并没有对象(Object),为什么呢?

那是因为对象属性的遍历先后顺序是不确定的,需要开发者手动指定。本质上,遍历器是一种线性处理,对于任何非线性的数据结构,部署遍历器接口就等于部署一种线性变换。

做如下处理,可以使对象供 for…of 消费:

// code1function Obj(value) {  this.value = value;  this.next = null;}Obj.prototype[Symbol.iterator] = function() {  var iterator = {    next: next  };  var current = this;  function next() {    if (current) {      var value = current.value;      current = current.next;      return {        done: false,        value: value      };    } else {      return {        done: true      };    }  }  return iterator;}var one = new Obj(1);var two = new Obj(2);var three = new Obj(3);one.next = two;two.next = three;for (var i of one) {  console.log(i);}// 1// 2// 3

登录后复制

2、调用 Iterator 接口的场合

(1) 解构赋值

// code2let set = new Set().add('a').add('b').add('c');let [x,y] = set;// x='a'; y='b'let [first, ...rest] = set;// first='a'; rest=['b','c'];

登录后复制

(2) 扩展运算符

// code3// 例一var str = 'hello';[...str] // ['h','e','l','l','o']// 例二let arr = ['b', 'c'];['a', ...arr, 'd']// ['a', 'b', 'c', 'd']

登录后复制

(3)Generator 函数中的 yield* 表达式(下一章介绍)

// code4let generator = function* () {yield 1;yield* [2,3,4];yield 5;};var iterator = generator();iterator.next() // { value: 1, done: false }iterator.next() // { value: 2, done: false }iterator.next() // { value: 3, done: false }iterator.next() // { value: 4, done: false }iterator.next() // { value: 5, done: false }iterator.next() // { value: undefined, done: true }

登录后复制

(4)其它场合

for..of

Array.from

Map()、Set()、WeakMap()、WeakSet()

Promise.all()

Promise.race()

3、for…of 循环的优势

先看看,数组 forEach 方法的缺点:

// code5myArray.forEach(function (value) { console.log(value);});

登录后复制

这个写法的问题在于,无法中途跳出 forEach 循环,break 命令或 return 命令都不能生效。

再看看,对象 for…in 的循环的缺点:

for (var index in myArray) { console.log(myArray[index]);};

登录后复制

数组的键名是数字,但是 for…in 循环是以字符串作为键名,“0”、“1”、“2”等。

for…in 循环不仅可以遍历数字键名,还会遍历手动添加的期推荐,甚至包括原型链上的键。

某些情况下,for…in 循环会议任意顺序遍历键名

for…in 遍历主要是为遍历对象而设计的,不适用于遍历数组

那么,for…of 有哪些显著的优点呢?

有着同 for…in 一样的简洁语法,但是没有 for…in 那些缺点

不同于 forEach 方法,它可以与 break、continue 和 return 配合使用

提供了遍历所有数据结构的统一操作接口

for (var n of fibonacci) { if (n > 1000) {  break;  console.log(n); }}

登录后复制

4、各数据类型如何使用 for…of 循环?

(1)数组

for…of 循环允许遍历数组获得键值

var arr = ['a', 'b', 'c', 'd'];for (let a in arr) {  console.log(a); // 0 1 2 3}for (let a of arr) {  console.log(a); // a b c d}

登录后复制

for…of 循环调用遍历器接口,数组的遍历器接口只返回具有数字索引的值

let arr = [3, 5, 7];arr.foo = 'hello';for (let i in arr) {  console.log(i); // "0", "1", "2", "foo"}for (let i of arr) {  console.log(i); // "3", "5", "7"}

登录后复制

(2)Map 和 Set 结构

var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);for (var e of engines) {  console.log(e);}// Gecko// Trident// Webkitvar es6 = new Map();es6.set("edition", 6);es6.set("committee", "TC39");es6.set("standard", "ECMA-262");for (var [name, value] of es6) {  console.log(name + ": " + value);}// edition: 6// committee: TC39// standard: ECMA-262

登录后复制

由上述的代码可以看出,for…of 循环遍历Map 和 Set 结构时,遍历的顺序是按照各个成员被添加进数据结构的顺序,Set 结构遍历时返回的是一个值,而 Map 结构遍历时返回的是一个数组,该数组的两个成员分别为当前 Map 成员的键名和键值。

(3)类数组对象

字符串

// 普通的字符串遍历let str = "yuan";for (let s of str) { console.log(s); // y u a n}// 遍历含有 32位 utf-16字符的字符串for (let x of 'auD83DuDC0A') { console.log(x);}// 'a'// 'uD83DuDC0A'

登录后复制

DOM NodeList 对象

let paras = document.querySelectorAll("p");for (let p of paras) { p.classList.add("test");}

登录后复制

arguments 对象

function printArgs() { for (let x of arguments) {  console.log(x); }}printArgs("a", "n");// "a"// "n"

登录后复制

没有 Iterator 接口类数组对象的遍历处理

借用 Array.from 方法处理

let arrayLike = {  length: 2,  0 : 'a',  1 : 'b'};// 报错for (let x of arrayLike) {  console.log(x);}// 正确for (let x of Array.from(arrayLike)) {  console.log(x);}

登录后复制

(4)对象

对于普通对象,不能直接使用 for…of 遍历,否则会报错,必须部署了 Iterator 接口才能使用。如下两种方法部署:

// 方法一:使用 Object.keys 方法讲对象的键名生成一个数组for (var key of Object.keys(someObject)) { console.log(key + ": " + someObject[key]);}// 方法二:使用Generator 函数将对象重新包装一下function * entries(obj) {  for (let key of Object.keys(obj)) {    yield[key, obj[key]];  }}for (let[key, value] of entries(obj)) {  console.log(key, "->", value);}// a -> 1// b -> 2// c -> 3

登录后复制

三、迭代器应用实例

1、斐波那契数列

下面我们就使用迭代器来自定义自己的一个斐波那契数列组,我们直到斐波那契数列有两个运行前提,第一个前提是初始化的前两个数字为0,1,第二个前提是将来的每一个值都是前两个值的和。这样我们的目标就是每次都迭代输出一个新的值。

var it = { [Symbol.iterator]() {    return this  },  n1: 0,  n2: 1,  next() {    let temp1 = this.n1,    temp2 = this.n2;    [this.n1, this.n2] = [temp2, temp1 + temp2]    return {      value: temp1,      done: false    }  }}for (var i = 0; i < 20; i++) {  console.log(it.next())}//   "value": 0,  "done": false} {  "value": 1,  "done": false} {  "value": 1,  "done": false} {  "value": 2,  "done": false} {  "value": 3,  "done": false} {  "value": 5,  "done": false}... {  "value": 2584,  "done": false} {  "value": 4181,  "done": false}

登录后复制

2、任务队列迭代器

我们可以定义一个任务队列,该队列初始化时为空,我们将待处理的任务传递后,传入数据进行处理。这样第一次传递的数据只会被任务1处理,第二次传递的只会被任务2处理… 代码如下:

var Task = {  actions: [],  [Symbol.iterator]() {    var steps = this.actions.slice();    return { [Symbol.iterator]() {        return this;      },      next(...args) {        if (steps.length > 0) {          let res = steps.shift()(...args);          return {            value: res,            done: false          }        } else {          return {            done: true          }        }      }    }  }}Task.actions.push(function task1(...args) {  console.log("任务一:相乘") return args.reduce(function(x, y) {    return x * y  })},function task2(...args) {  console.log("任务二:相加") return args.reduce(function(x, y) {    return x + y  }) * 2},function task3(...args) {  console.log("任务三:相减") return args.reduce(function(x, y) {    return x - y  })});var it = Task[Symbol.iterator]();console.log(it.next(10, 100, 2));console.log(it.next(20, 50, 100)) console.log(it.next(10, 2, 1)) // 任务一:相乘 {  "value": 2000,  "done": false}任务二:相加 {  "value": 340,  "done": false}任务三:相减 {  "value": 7,  "done": false}

登录后复制

3、延迟执行

假设我们有一个数据表,我们想按大小顺序依次的获取数据,但是我们又不想提前给他排序,有可能我们根本就不去使用它,所以我们可以在第一次使用的时候再排序,做到延迟执行代码:

var table = {  "d": 1,  "b": 4,  "c": 12,  "a": 12}table[Symbol.iterator] = function() {  var _this = this;  var keys = null;  var index = 0;  return {    next: function() {      if (keys === null) {        keys = Object.keys(_this).sort();      }      return {        value: keys[index],        done: index++>keys.length      };    }  }}for (var a of table) {  console.log(a)} // a b c d

登录后复制

四、结语

本章内容,重点是明白 Iterator 接口的机制,以及 for…of 循环的使用方法。

相关推荐:

ES6可迭代协议和迭代器协议详解

关于PHP聚合式迭代器接口IteratorAggregate用法分享

关于js 迭代器方法

以上就是ES6迭代器(Iterator)和 for.of循环使用方法的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2786815.html

(0)
上一篇 2025年3月8日 17:53:41
下一篇 2025年3月8日 17:53:49

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • shell中$使用方法解释

    linux中shell变量$#,$@,$0,$1,$2的含义解释: 变量说明: $$ shell本身的pid(processid) $! shell最后运行的后台process的pid $? 最后运行的命令的结束代码(返回值) $- 使用s…

    编程技术 2025年3月8日
    200
  • Promise的基本使用方法教程

    本文主要和大家分享promise的基本使用方法教程,个人理解就是使用同步编程的写法完成异步编程操作。希望能帮助到大家。 const promise = new Promise((resolve, reject) => { //some…

    编程技术 2025年3月8日
    200
  • layui上传组件使用方法分享

    本文主要和大家分享layui上传组件使用方法,先贴上前端的代码,希望能帮助到大家。 产品特性Form @*table { height: 150px; } .layui-form-label { width: 100px; }*@ 选择多文…

    编程技术 2025年3月8日
    200
  • JsChart组件使用方法简介

    jschart是什么?jschart能够在网页上生成图标,常用于统计信息,十分好用的一个js组件。 使用JsChart 一。导入jscharts.js  二。编写jscharts.jsp测试页面 1.下载JScharts库 从官网下载JSc…

    编程技术 2025年3月8日
    200
  • ckeditor自定义插件使用方法解析

    ckeditor即大名鼎鼎的fckeditor,该公司的另一个产品为ckfinder(一个ajax文件管理器)。ckeditor是一款功能强大的富文本编辑工具,这篇文章主要为大家详细介绍了ckeditor自定义插件的使用方法,具有一定的参考…

    2025年3月8日
    200
  • js中字符串使用方法分享

    本文主要和大家分享js中字符串使用方法,文中运用了多个例子,希望能帮助到大家。 1.提取字符串substring() substring() 方法用于提取字符串中介于两个指定下标之间的字符。 语法 stringObject.substrin…

    编程技术 2025年3月8日
    200
  • clipboard.js基本使用方法分享

    clipboard.js 是一个不需要flash,将文本复制到剪贴板的插件。本文主要和大家介绍clipboard.js基本使用方法,希望能帮助到大家。 1 引入插件 登录后复制 2基本使用 首先需要您需要通过传递DOM选择器,HTML元素或…

    编程技术 2025年3月8日
    200
  • js中的sort()使用方法

    如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以便进行比较。 array.sort()方法默认是升序排序,如果想按照…

    编程技术 2025年3月8日
    200
  • js中slice()使用方法

    本文主要和大家分享js中slice()使用方法,slice()通过索引位置获取新的数组,该方法不会修改原数组,只是返回一个新的子数组。 用法:arrayobj.slice(start,end) arrayObj – 原始数组; …

    编程技术 2025年3月8日
    200
  • jquery里的on和click的使用方法

    这次给大家带来jquery里的on和click的使用方法,使用jquery里的on与click的注意事项有哪些,下面就是实战案例,一起来看一下。 使用jQuery写js时,有些用on写行为函数,有些用click,弄清二者区别很重要。 以下是…

    2025年3月8日
    200

发表回复

登录后才能评论