了解ES6中的for … of循环和Iterable对象

了解ES6中的for ... of循环和Iterable对象

推荐教程:《JavaScript视频教程》

本文将研究 ES6 的 for … of 循环。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

旧方法

在过去,有两种方法可以遍历 javascript

首先是经典的 for i 循环,它使你可以遍历数组或可索引的且有 length 属性的任何对象。

for(i=0;i<things.length;i++) {    var thing = things[i]    /* ... */}

登录后复制

其次是 for … in 循环,用于循环一个对象的键/值对。

for(key in things) {    if(!thing.hasOwnProperty(key)) { continue; }    var thing = things[key]    /* ... */}

登录后复制

for … in 循环通常被视作旁白,因为它循环了对象的每一个可枚举属性。这包括原型链中父对象的属性,以及被分配为方法的所以属性。换句话说,它遍历了一些人们可能想不到的东西。使用 for … in 通常意味着循环块中有很多保护子句,以避免出现不需要的属性。

早期的 javascript 通过库解决了这个问题。许多 JavaScript库(例如:Prototype.js,jQuery,lodash 等)都有类似 each 或 foreach 这样的工具方法或函数,可让你无需 for i 或 for … in 循环去遍历对象和数组。

for … of 循环是 ES6 试图不用第三方库去解决其中一些问题的方式。

for … of

for … of 循环

for(const thing of things) {    /* ... */}

登录后复制

它将遍历一个可迭代(iterable)对象。

可迭代对象是定义了 @@ iterator 方法的对象,而且 @@iterator 方法返回一个实现了迭代器协议的对象,或者该方法是生成器函数。

在这句话中你需要理解很多东西:

可迭代的对象@@iterator方法( @@是什么意思?)迭代器协议(这里的协议是什么意思?)等等,迭代(iterable)和迭代器(iterator)不是一回事?另外,生成器函数又是什么鬼?

下面逐个解决这些疑问。

内置 Iterable

首先,javascript 对象中的一些内置对象天然的可以迭代,比如最容易想到的就是数组对象。可以像下面的代码中一样在 for … of 循环中使用数组:

const foo = ['apples','oranges','pears']for(const thing of foo) {  console.log(thing)}

登录后复制

输出结果是数组中的所有元素。

applesorangespears

登录后复制

还有数组的 entries 方法,它返回一个可迭代对象。这个可迭代对象在每次循环中返回键和值。例如下面的代码:

const foo = ['apples','oranges','pears']for(const thing of foo.entries()) {  console.log(thing)}

登录后复制

将输出以下内容

[ 0, 'apples' ][ 1, 'oranges' ][ 2, 'pears' ]

登录后复制

当用下面的语法时,entries 方法会更有用

const foo = [    'apples','oranges','pears']for(const [key, value] of foo.entries()) {  console.log(key,':',value)}

登录后复制

在 for 循环中声明了两个变量:一个用于返回数组的第一项(值的键或索引),另一个用于第二项(该索引实际对应的值)。

一个普通的 javascript 对象是不可迭代的。如果你执行下面这段代码:

// 无法正常执行const foo = {  'apples':'oranges',  'pears':'prunes'}for(const [key, value] of foo) {  console.log(key,':',value)}

登录后复制

会得到一个错误

$ node test.js/path/to/test.js:6for(const [key, value] of foo) {TypeError: foo is not iterable

登录后复制

然而全局 Object 对象的静态 entries 方法接受一个普通对象作为参数,并返回一个可迭代对象。就像这样的程序:

const foo = {  'apples':'oranges',  'pears':'prunes'}for(const [key, value] of Object.entries(foo)) {  console.log(key,':',value)}

登录后复制

能够得到你期望的输出:

$ node test.jsapples : orangespears : prunes

登录后复制

创建自己的 Iterable

如果你想创建自己的可迭代对象,则需要花费更多的时间。你会记得前面说过:

可迭代对象是定义了 @@ iterator 方法的对象,而且 @@iterator 方法返回一个实现了迭代器协议的对象,或者该方法是生成器函数。

搞懂这些内容的最简单方法就是一步一步的去创建可迭代对象。首先,我们需要一个实现 @@iterator 方法的对象。  @@ 表示法有点误导性,我们真正要做的是用预定义的 Symbol.iterator 符号定义方法。

如果用迭代器方法定义对象并尝试遍历:

const foo = {  [Symbol.iterator]: function() {  }}for(const [key, value] of foo) {  console.log(key, value)}

登录后复制

得到一个新错误:

for(const [key, value] of foo) {                          ^TypeError: Result of the Symbol.iterator method is not an object

登录后复制

这是 javascript 告诉我们它在试图调用 Symbol.iterator 方法,但是调用的结果不是对象。

为了消除这个错误,需要用迭代器方法来返回实现了迭代器协议的对象。这意味着迭代器方法需要返回一个有 next 键的对象,而 next 键是一个函数。

const foo = {  [Symbol.iterator]: function() {    return {      next: function() {      }    }  }}for(const [key, value] of foo) {  console.log(key, value)}

登录后复制

如果运行上面的代码,则会出现新错误。

for(const [key, value] of foo) {                     ^TypeError: Iterator result undefined is not an object

登录后复制

这次 javascript 告诉我们它试图调用 Symbol.iterator 方法,而该对象的确是一个对象,并且实现了 next 方法,但是 next 的返回值不是 javascript 预期的对象。

next 函数需要返回有特定格式的对象——有 value 和 done 这两个键。

next: function() {    //...    return {        done: false,        value: 'next value'    }}

登录后复制

done 键是可选的。如果值为 true(表示迭代器已完成迭代),则说明迭代已结束。

如果 done 为 false 或不存在,则需要 value 键。 value 键是通过循环此应该返回的值。

所以在代码中放入另一个程序,它带有一个简单的迭代器,该迭代器返回前十个偶数。

class First20Evens {  constructor() {    this.currentValue = 0  }  [Symbol.iterator]() {    return {      next: (function() {        this.currentValue+=2        if(this.currentValue > 20) {          return {done:true}        }        return {          value:this.currentValue        }      }).bind(this)    }  }}const foo = new First20Evens;for(const value of foo) {  console.log(value)}

登录后复制

生成器

手动去构建实现迭代器协议的对象不是唯一的选择。生成器对象(由生成器函数返回)也实现了迭代器协议。上面的例子用生成器构建的话看起来像这样:

class First20Evens {  constructor() {    this.currentValue = 0  }  [Symbol.iterator]() {    return function*() {      for(let i=1;i<=10;i++) {        if(i % 2 === 0) {          yield i        }      }    }()  }}const foo = new First20Evens;for(const item of foo) {  console.log(item)}

登录后复制

本文不会过多地介绍生成器,如果你需要入门的话可以看这篇文章。今天的重要收获是,我们可以使自己的 Symbol.iterator 方法返回一个生成器对象,并且该生成器对象能够在 for … of 循环中“正常工作”。 “正常工作”是指循环能够持续的在生成器上调用 next,直到生成器停止 yield 值为止。

$ node sample-program.js246810

登录后复制

原文地址:https://alanstorm.com/es6s-many-for-loops-and-iterable-objects/

作者:Alan Storm

译文地址:https://segmentfault.com/a/1190000023924865

更多编程相关知识,请访问:编程学习网站!!

以上就是了解ES6中的for … of循环和Iterable对象的详细内容,更多请关注【创想鸟】其它相关文章!

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

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

(0)
上一篇 2025年3月7日 23:12:32
下一篇 2025年2月19日 10:39:48

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

相关推荐

  • JavaScript中var,let与const的区别是什么?

    区别:1、var声明的变量属于函数作用域,let和const声明的变量属于块级作用域;2、var存在变量提升现象,而let和const没有;3、var变量可以重复声明,而在同一块级作用域,let变量不能重新声明,const变量不能修改。 推…

    2025年3月7日
    200
  • JavaScript的三大组成部分是什么

    JavaScript的三大组成部分是:1、ECMAscript;2、文档对象模型DOM;3、浏览器对象模型BOM。其中,ECMAscript是javascript的核心,描述了语言的基本语法和数据类型。 JavaScript的三大组成部分是…

    2025年3月7日
    200
  • JavaScript charAt()方法是什么

    JavaScript charAt()方法是可返回指定位置的字符,语法为【stringObject.charAt(index)】,其中index表示字符串中某个位置的数字,即字符在字符串中的下标。 定义和用法 charAt() 方法可返回指…

    2025年3月7日
    200
  • 详解JS中的垃圾回收和内存泄漏

    程序的运行需要内存。只要程序提出要求,操作系统或者运行时就必须供给内存。所谓的内存泄漏简单来说是不再用到的内存,没有及时释放。为了更好避免内存泄漏,我们先介绍Javascript垃圾回收机制。 在C与C++等语言中,开发人员可以直接控制内存…

    2025年3月7日 编程技术
    200
  • 深入讨论JavaScript中Set对象如何让代码更快

    我确信有很多开发人员坚持使用基本的全局对象:数字,字符串,对象,数组和布尔值。对于许多用例,这些都是需要的。 但是如果想让你的代码尽可能快速和可扩展,那么这些基本类型并不总是足够好。 在本文中,我们将讨论JS 中Set对象如何让代码更快— …

    2025年3月7日
    200
  • javascript中substr和substring的区别是什么

    javascript中substr和substring的区别是:substr是从起始索引号开始提取指定长度的字符串;substring是提取字符串中两个指定索引号之间的字符。 区别介绍: (视频学习分享:javascript视频教程) su…

    2025年3月7日
    200
  • 你所不知道的JavaScript

    JavaScript栏目介绍一些必会操作。 和其他“圈子”里的同学们不一样,前端圈子里的同学们都很热衷于“手写xxx方法”,基本上每天在掘金里都可以看到类似的文章。但是,很多文章(不代表全部,无意冒犯)大都是囫囵吞枣、依葫芦画瓢,经不起推敲…

    2025年3月7日
    200
  • 同时去掉字符串左边和右边空格的函数是什么?

    同时去掉字符串左边和右边空格的函数是“trim()”;trim()函数可用于删除字符串的头尾空白符,空白符包括:空格、制表符tab、换行符等其他空白符等,语法“string.trim()”。 本教程操作环境:windows10系统、java…

    2025年3月7日
    200
  • javascript如何改变原数组

    javascript改变原数组的方法:1、push往数组里面增加东西;2、pop把数组最后一位元素剪切出去;3、unshit是往数组第一位元素前面添加元素;4、shit从数组前面的第一位元素开始删除。 本教程操作环境:windows10系统…

    2025年3月7日 编程技术
    200
  • javascript提高前端代码强大的一些方法,很好!

    javascript栏目介绍提高前端代码强大的一些方法。 免费推荐:JavaScript(视频) 在过去的开发经历中处理了各种奇葩BUG,认识到代码健壮性(鲁棒性)是提高工作效率、生活质量的一个重要指标,本文主要整理了提高代码健壮性的一些思…

    2025年3月7日
    200

发表回复

登录后才能评论