为什么说JavaScript中for...of循环是一颗宝石

是什么使得一个编程语言的新特性很棒?那就是当这个特性可以结合多个其它特性的时候。

ES2015 版本中引入的 for...of 语句就是这种情况。

for...of 可以迭代数组、类数组以及任何可以迭代的对象(mapssetsDOM集合),并且,for...of 的语句还很短。

在这篇文章中,我将会演示 for...of 的能力。

1. 数组迭代

for...of 最常见的应用是对数组项进行迭代。该循环可以高效得完成迭代,而无需其他变量来保持索引。

例如:

const products = ['oranges', 'apples'];

for (const product of products) {
  console.log(product);
}
// 'oranges'
// 'apples'

for...of 循环遍历 products 的每一项。迭代项被赋值给变量 product.

数组方法 entries() 可以用于访问迭代项的索引。该方法在每次迭代时返回一对 [index,item]

就地解构是 for...of 的另一个重要功能,我们将在下一部分中对其进行详细说明。

1.1 就地解构

首先,我们来看一下 for...of 循环的语法:

for (LeftHandSideExpression of Expression) {
  // statements
}

LeftHandSideExpression 表达式可以替换为任意赋值表达式左侧的内容。

在前面的示例中,LeftHandSideExpression 是一个变量声明 const product ,甚至是一个解构 const [index,product]

因此,for...of 的语法支持实现迭代项的解构。

让我们遍历一个对象数组,提取每个对象的 name 属性:

const persons = [
  { name: 'John Smith' },
  { name: 'Jane Doe' }
];

for (const { name } of persons) {
  console.log(name);
}
// 'John Smith'
// 'Jane Doe'

const { name } of persons 循环迭代 persons 对象数组,并且就地将 person 对象进行了解构。

2. 类数组迭代

for...of 可以用于迭代类数组对象。arguments 是函数体内的特殊变量,包含函数的所有参数,这是一个经典的类数组对象。

让我们写一个求和函数 sum(num1, num2, ..., numN)

function sum() {
  let sum = 0;
  for (const number of arguments) {
    sum += number;
  }
  return sum;
}

sum(1, 2, 3); // => 6

在每次迭代中,for...of 循环遍历类数组 arguments 中的每一个数,并计算总和。

3. 快速了解可迭代

什么是可迭代对象?它是支持可迭代协议的对象。

我们可以通过查看 Symbol.iterator 方法来确定某个数据是否可迭代。例如,下面的例子显示了数组是可迭代的:

const array = [1, 2, 3];
const iterator1 = array[Symbol.iterator]();
iterator1.next(); // => { value: 1, done: false }

如果你想了解更多信息,可以随时阅读我之前的文章。

for...of 接受可迭代对象。这很棒,因为现在你可以遍历string、数组、类数组、setmap,同时仍可以享受 for...of 的简洁。

4. 字符串迭代

JavaScript 的基础类型 string 是可迭代的。因此,可以轻松地遍历字符串的字符。

const message = 'hello';

for (const character of message) {
  console.log(character);
}
// 'h'
// 'e'
// 'l'
// 'l'
// 'o'

message 是一个字符串。由于字符串可迭代的,因此 for...of 循环遍历 message

5. Map 和 Set 迭代

Map 是一个特殊的对象,将键与值相关联。键可以是任何基本类型(通常是 string,但可以是 number 等)。

幸运的是,Map 也是可迭代的(在键/值对上进行迭代),并且 for...of 可以轻松地循环迭代所有键/值对。

一起看一下:

const names = new Map();
names.set(1, 'one');
names.set(2, 'two');

for (const [number, name] of names) {
  console.log(number, name);
}
// logs 1, 'one'
// logs 2, 'two'

for (const [number, name] of names) 迭代 names 的键值对。

在每个循环中,迭代器都会返回一个数组 [key,value] ,并使用 const [number,name] 立即对这对数组进行解构。

以相同的方式可以遍历 Set 的项:

const colors = new Set(['white', 'blue', 'red', 'white']);

for (color of colors) {
  console.log(color);
}
// 'white'
// 'blue'
// 'red'

6. 迭代普通的JavaScript对象

尝试遍历普通JS对象的属性/值总是很痛苦。过去,我通常使用 Object.keys() 获取对象的键,然后使用 forEach 来迭代键数组。【译者:这不代表本人观点,我比较喜欢用 for...in 遍历对象】

const person = {
  name: 'John Smith',
  job: 'agent'
};

Object.keys(person).forEach(prop => {
  console.log(prop, person[prop]);
});
// 'name', 'John Smith'
// 'job', 'agent'

新的 Object.entries() 函数与 for...of 组合使用是个不错的选择:

const person = {
  name: 'John Smith',
  job: 'agent'
};

for (const [prop, value] of Object.entries(person)) {
  console.log(prop, value);
}
// 'name', 'John Smith'
// 'job', 'agent'

Object.entries(person) 返回一个键和值的元组数组:[[''name','John Smith'],['job','agent']]。然后,使用 for...of 循环遍历数组,并将每个元组解构为 const [prop,value]

7. 遍历DOM集合

你可能知道 HTMLCollection 令人沮丧。主要是因为 HTMLCollection 是一个类数组的对象(而不是常规数组),所以我们无法使用数组的方法。

例如,每个 DOM 元素的 children 属性都是 HTMLCollection 。好在 for...of 可以在类似数组的对象上进行迭代,因此我们可以轻松地迭代 children

const children = document.body.children;

for (const child of children) {
  console.log(child); // logs each child of <body>
}

此外,for...of 可以迭代 NodeList 集合(可迭代)。例如,函数 document.querySelectorAll(query) 返回一个 NodeList

const allImages = document.querySelectorAll('img');

for (const image of allImages) {
  console.log(image); // log each image in the document
}

如果你想遍历 DOM 中的不同种类的集合,那么 for...of 语句是一个不错的选择。

8. 性能

迭代大型数组时,for...of 的执行速度可能会比经典方法慢:

const a = [/* big array */];
for (let i = 0; i < a.length; i++) {
  console.log(a[i]);
}

在每次迭代中调用迭代器比通过增加索引访问的开销更大。但是,这种细微差别在使用大型数组的应用程序中以及性能至关重要的应用程序中非常重要,不过这种情况很少发生。

9. 总结

为什么说 for...of 是一颗宝石,因为:

  • 它简明扼要
  • 它接受迭代器,包括数组,字符串,SetMap,DOM集合
  • 它接受类数组对象
  • 迭代的项目可以在就地解构。

你首选的迭代数组项的方式是什么?

最后:

原文地址: https://dmitripavlutin.com/javascript-for-of/

点评:翻译得很烂,还不如机翻。哈哈哈哈。


推荐文章
如何使用JavaScript删除表中的表行?

语法:node.remove()示例1:首先根据id值选择行,然后使用remove()方法删除它。 tabletr{ background:#e46060ed; color:white;

web前端JavaScript面试试题(附答案)

1.介绍js的基本数据类型Undefined、Null、Boolean、Number、String、ECMAScript2015新增:Symbol(创建后独一无二且不可变的数据类型)2.介绍js有哪些

常用JS数组操作方法(含ES6)

一、concat()concat()方法用于连接两个或多个数组。该方法不会改变现有的数组,仅会返回被连接数组的一个副本。vararr1=[1,2,3]; vararr2=[4,5]; vararr3=

Canvas中颜色过渡动画效果的实现

但是,在中却没有这么简单,因为本质上是一个静态画布,要想实现颜色变化,需要JS去不断绘制,实现起来要比CSS实现麻烦很多。再加上颜色值本身就不一定是纯粹的数值,更增加了我们实现的难度。本文就将通过多个

什么是LiveScript?

LiveScript的创造者是BrendanEich,首次在NetScape2中实现。它的目的是创建一门足够简单的语言让开发者能容易地为网页增加交互,只要把代码拷贝过来调整一下就可以。很多LiveSc

select发展史 超强第1/2页

select,option{background-color:lime} 1 2 不是一样的嘛 select,option{background-color:lime;font

JavaScript中的BOM对象介绍

一.Window对象1、简单说明所有的浏览器都支持window对象;从概念上来讲,一个HTML文档对应一个window对象;从功能上来说,它可以控制浏览器的窗口;从使用上讲,window对象不需要创建

JavaScript如何工作:内存管理+如何处理4个常见的内存泄漏

概述像C这样的编程语言,具有低级内存管理原语,如malloc()和free()。开发人员使用这些原语显式地对操作系统的内存进行分配和释放。而JavaScript在创建对象(对象、字符串等)时会为它们分

36个工作中常用的JavaScript函数片段

如果文章和笔记能带您一丝帮助或者启发,请不要吝啬你的赞和收藏,你的肯定是我前进的最大动力附笔记链接,阅读往期更多优质文章可移步查看,喜欢的可以给我点赞鼓励哦:https://github.com/Ws

JavaScript作用域链图文详解

单纯的JavaScript作用域还是很好理解的,在一些类C编程语言中花括号内的每一段代码都有各自的作用域,而且变量在声明它们的代码段外是不可见的,称之为块级的作用域。JavaScript容易让初学者误

Javascript 面试中经常被问到的三个问题!

然,这些并不是你在面试之前应该学习的唯一三件事-你可以通过多种方式更好地为即将到来的面试做准备-但面试官可能会问到下面是三个问题,来判断你对JavaScript语言的理解和DOM的掌握程度。让我们开始

JavaScript中缩短箭头函数的小诀窍

使用箭头语法,你可以定义比函数表达式短的函数。在某些情况下,你可以完全省略:参数括号(param1,param2)return关键字甚至大括号{}。下面就让我们来探讨一下如何使箭头函数简洁明了、易于阅

14 个拷贝数组的 JS 技巧

这意味着要拷贝一个数组,咱们不能简单地将旧数组分配给一个新变量,它也是一个数组。如果这样做,它们将共享相同的引用,并且在更改一个变量之后,另一个变量也将受到更改的影响。这就是我们需要克隆这个数组的原因

javascript怎么判断字符是否是中文?

方法一、用正则表达式判断:正则表达式(regularexpression)是一个描述字符模式的对象。ECMAScript的RegExp类表示正则表达式,而String和RegExp都定义了使用正则表达

如何写出优雅耐看的JavaScript代码

干净的代码,既在质量上较为可靠,也为后期维护、升级奠定了良好基础。我们从以下几个方面进行探讨:变量1、变量命名一般我们在定义变量是要使用有意义的词汇命令,要做到见面知义//badcode consty

JAVAScript学习-序列化、转义和函数

序列化:把JS对象转换成JSON格式JSON.stringify(obj)序列化 JSON.parse(str)反序列化varls=[1,2,3,4]; varls_st=JSON.stringify

5个ES10的新特性介绍

1、Object.fromEntries()在JavaScript中,将数据从一种格式转换为另一种格式非常常见。为了便于将对象转换为数组,ES2017引入了Object.entrie()方法。此方法将

详解JavaScript构造器

构造函数跟普通函数非常相似,但是我们通过new关键字来使用它们。主要有两种类型的构造函数,native构造函数(Array,Object)它们可以在执行环境中自动生成,还有自定义的构造函数,你可以定义

JavaScript的共享传递和按值传递介绍

按值传递和引用传递参数主要区别简单可以说:按值传递:在函数里面改变传递的值不会影响到外面引用传递:在函数里面改变传递的值会影响到外面但答案是JavaScript对所有数据类型都使用按值传递。它对数组和

聊聊TypeScript中的类型断言(type assertions)

本文是关于TypeScript中的typeassertions的,它与其他语言中的类型强制转换有相似之处,并通过as运算符执行。类型断言类型断言使我们可以覆盖TypeScript为存储位置计算的静态类