Skip to content

AI编程自学网

ai2opencode您的编程助手

Menu
  • 网站首页
  • WordPress专栏
  • 程序员内功
  • 副业和涨工资
  • Windows11
Menu

Javascript问答之在 JavaScript 中的数组上的 For-each

Posted on 2021年7月30日 by ai2opencode

实战问题

如何使用 JavaScript 遍历数组中的所有条目?

我以为是这样的:

forEach(instance in theArray)
theArray我的数组在哪里,但这似乎不正确。

解决方案

1.使用for-of(隐式使用迭代器)(ES2015+)

ES2015向 JavaScript添加了迭代器和可迭代对象。数组是可迭代的(字符串、Maps 和Sets 以及 DOM 集合和列表也是如此,稍后您将看到)。可迭代对象为其值提供迭代器。newfor-of语句循环遍历迭代器返回的值:

const a = ["a", "b", "c"];
for (const val of a) { // You can use `let` instead of `const` if you like
    console.log(val);
}
// a
// b
// c

2.用途forEach及相关

在任何可以访问ArrayES5 添加的功能的模糊现代环境(因此,不是 IE8)中,如果您只处理同步代码(或者您不需要等待),则可以使用forEach( spec | MDN )用于在循环期间完成的异步进程):

const a = ["a", "b", "c"];
a.forEach((entry) => {
    console.log(entry);
});

3. 使用简单的for循环

有时旧的方法是最好的:

const a = ["a", "b", "c"];
for (let index = 0; index < a.length; ++index) {
    console.log(a[index]);
}

4、正确使用for-in

for-in不是用于遍历数组,而是用于遍历对象属性的名称。作为数组是对象这一事实的副产品,它似乎经常用于循环遍历数组,但它不仅循环遍历数组索引,还循环遍历对象的所有可枚举属性(包括继承的属性)。(也曾经是没有指定顺序;现在是[详情在这个其他答案中],但是即使现在指定了顺序,规则也很复杂,也有例外,依赖顺序不是最佳实践。

// `a` is a sparse array
const a = [];
a[0] = "a";
a[10] = "b";
a[10000] = "c";
for (const name in a) {
    if (a.hasOwnProperty(name)  &&      // These checks are
        /^0$|^[1-9]\d*$/.test(name) &&  // explained
        name <= 4294967294              // below
       ) {
        console.log(a[name]);
    }
}

TL; 博士

你最好的选择通常是

一个for-of循环(仅限 ES2015+;规范| MDN)——简单且async友好
forEach(ES5 +只;规格| MDN)(或其亲属some和这样) -不 async-友好(而见详情)
一个简单的老式for循环——async友好
(很少) for-in 有保护措施- -async友好
一些快速的“不要”:

不要使用,for-in除非您在安全措施下使用它或者至少知道它为什么会咬你。
不要使用map,如果你不使用它的返回值。
(可悲的是有人在那里教map[ spec / MDN ] 好像它是forEach - 但这不是它的用途。如果您不使用它创建的数组,请不要使用map。)
不要使用forEach,如果回调不异步工作,并且希望forEach等到这项工作完成(因为它不会)。
但是还有很多东西要探索,请继续阅读...

JavaScript 具有强大的语义来循环遍历数组和类数组对象。我将答案分为两部分:真正数组的选项,以及类似数组的选项,例如arguments对象、其他可迭代对象 (ES2015+)、DOM 集合等。

好的,让我们看看我们的选择:

对于实际数组
您有五个选项(两个基本上永久支持,另一个由 ECMAScript 5 [“ES5”] 添加,另外两个在 ECMAScript 2015(“ES2015”,又名“ES6”)中添加:

使用for-of(隐式使用迭代器)(ES2015+)
使用forEach及相关(ES5+)
使用简单的for循环
正确使用for-in
显式使用迭代器(ES2015+)
(你可以在这里看到那些旧的规范:ES5,ES2015,但两者都被取代了;当前编辑的草稿总是在这里。)

细节:

1.使用for-of(隐式使用迭代器)(ES2015+)
ES2015向 JavaScript添加了迭代器和可迭代对象。数组是可迭代的(字符串、Maps 和Sets 以及 DOM 集合和列表也是如此,稍后您将看到)。可迭代对象为其值提供迭代器。newfor-of语句循环遍历迭代器返回的值:

const a = ["a", "b", "c"];
for (const val of a) { // You can use let instead of const if you like
console.log(val);
}
// a
// b
// c
展开片段
没有比这更简单的了!在幕后,它从数组中获取一个迭代器并遍历迭代器返回的值。数组提供的迭代器提供数组元素的值,从开始到结束。

注意val每个循环迭代的范围如何;尝试val在循环结束后使用会失败,因为它不存在于循环体之外。

理论上,一个for-of循环涉及多个函数调用(一个用于获取迭代器,然后一个用于从中获取每个值)。即使这是真的,也没有什么可担心的,现代 JavaScript 引擎中的函数调用非常便宜(它困扰着我forEach[below] 直到我研究它;细节)。但此外,在处理数组等本机迭代器时,JavaScript 引擎会优化这些调用(在性能关键代码中)。

for-of是完全async友好的。如果您需要在循环体中串行(而不是并行)完成工作,则循环体中的一个awaitin 循环体将在继续之前等待承诺解决。这是一个愚蠢的例子:

显示代码片段

请注意这些词是如何在每个词之前延迟出现的。

这是一个编码风格的问题,但这for-of是我在遍历任何可迭代的东西时首先要达到的。

2.用途forEach及相关
在任何可以访问ArrayES5 添加的功能的模糊现代环境(因此,不是 IE8)中,如果您只处理同步代码(或者您不需要等待),则可以使用forEach( spec | MDN )用于在循环期间完成的异步进程):

const a = ["a", "b", "c"];
a.forEach((entry) => {
console.log(entry);
});
展开片段
forEach接受一个回调函数和一个可选的值,作为this调用该回调时使用的值(上面没有使用)。为数组中的每个条目调用回调,按顺序跳过稀疏数组中不存在的条目。虽然我只使用了上面的一个参数,但回调是用三个参数调用的:每个条目的值、该条目的索引以及对您正在迭代的数组的引用(以防您的函数还没有它便利)。

像for-of,forEach的优点是您不必在包含范围内声明索引和值变量;在这种情况下,它们作为迭代函数的参数提供,并且很好地限定在该迭代中。

与for-of,forEach的缺点是它不理解async函数和await. 如果您使用async函数作为回调,forEach则在继续之前不等待该函数的承诺解决。这是使用替代的async示例- 请注意初始延迟是如何出现的,但随后所有文本都会立即出现而不是等待:for-offorEach

显示代码片段

forEach 是“循环遍历所有”函数,但 ES5 定义了其他几个有用的“遍历数组并执行操作”函数,包括:

every( spec | MDN ) - 回调第一次返回假值时停止循环
some( spec | MDN ) - 回调第一次返回真值时停止循环
filter( spec | MDN ) - 创建一个新数组,其中包含回调返回真值的元素,省略不返回真值的元素
map( spec | MDN ) - 从回调返回的值创建一个新数组
reduce( spec | MDN ) - 通过重复调用回调来建立一个值,传入以前的值;有关详细信息,请参阅规范
reduceRight( spec | MDN ) - 类似reduce,但按降序而不是升序工作
与 一样forEach,如果你使用一个async函数作为你的回调函数,那么这些函数都不会等待函数的承诺完成。这意味着:

使用一个async回调函数从来没有通过适当的every,some以及filter因为它们将把返回的承诺,就好像是一个truthy值; 他们不会等待承诺解决,然后使用履行价值。
使用async函数回调通常适用于map,如果目标是将某物的数组转换为promise的数组,可能是为了传递给其中一个 promise 组合器函数(Promise.all、Promise.race、promise.allSettled、 或Promise.any)。
使用async函数回调很少适合与reduceor reduceRight,因为(再次)回调将始终返回一个承诺。但是有一种习惯用法是从使用reduce( const promise = array.reduce((p, element) => p.then(/...something using element.../));)的数组构建承诺链,但通常在这些情况下,函数中的for-oforfor循环async会更清晰且更易于调试。

  1. 使用简单的for循环
    有时旧的方法是最好的:

const a = ["a", "b", "c"];
for (let index = 0; index < a.length; ++index) {
console.log(a[index]);
}
展开片段
如果数组的长度将不会在循环过程中改变,它在性能敏感的代码(不可能),一个稍微复杂一点的版本抓住了长度达阵可能是一个很小的有点快:

const a = ["a", "b", "c"];
for (let index = 0, len = a.length; index < len; ++index) {
console.log(a[index]);
}
展开片段
和/或倒数:

const a = ["a", "b", "c"];
for (let index = a.length - 1; index >= 0; --index) {
console.log(a[index]);
}
展开片段
但是对于现代 JavaScript 引擎,您很少需要勉强挤出最后一点汁水。

在 ES2015 之前,循环变量必须存在于包含作用域中,因为var只有函数级作用域,没有块级作用域。但是正如您在上面的示例中看到的,您可以let在 内使用for将变量范围限定为循环。当你这样做时,index变量会为每次循环迭代重新创建,这意味着在循环体中创建的闭包保留index对特定迭代的引用,这解决了旧的“循环中的闭包”问题:

显示代码片段

在上面,如果你点击第一个,你会得到“Index is: 0”,如果你点击最后一个,你会得到“Index is: 4”。这并没有,如果你使用的工作var,而不是let。

就像for-of,for循环在async函数中运行良好。这是使用for循环的较早示例:

显示代码片段

4、正确使用for-in
for-in不是用于遍历数组,而是用于遍历对象属性的名称。作为数组是对象这一事实的副产品,它似乎经常用于循环遍历数组,但它不仅循环遍历数组索引,还循环遍历对象的所有可枚举属性(包括继承的属性)。(也曾经是没有指定顺序;现在是[详情在这个其他答案中],但是即使现在指定了顺序,规则也很复杂,也有例外,依赖顺序不是最佳实践。)

for-in数组上唯一真正的用例是:

它是一个稀疏数组,其中有大量间隙,或者
您正在使用非元素属性,并且希望将它们包含在循环中
仅查看第一个示例:for-in如果您使用适当的保护措施,您可以使用访问那些稀疏数组元素:

// a is a sparse array
const a = [];
a[0] = "a";
a[10] = "b";
a[10000] = "c";
for (const name in a) {
if (a.hasOwnProperty(name) && // These checks are
/^0$|^[1-9]\d*$/.test(name) && // explained
name <= 4294967294 // below
) {
console.log(a[name]);
}
}
展开片段
注意三项检查:

该对象具有该名称的属性(不是从其原型继承的属性),并且

名称都是十进制数字(例如,正常的字符串形式,而不是科学记数法),以及

强制为数字时名称的值为 <= 2^32 - 2(即 4,294,967,294)。这个数字从哪里来?它是规范中数组索引定义的一部分。其他数字(非整数、负数、大于 2^32 - 2 的数字)不是数组索引。它是 2^32 - 2的原因是这使得最大索引值低于 2^32 - 1,这是数组length可以具有的最大值。(例如,数组的长度适合 32 位无符号整数。)

当然,您不会在内联代码中这样做。你会写一个实用程序函数。可能:

显示代码片段

...尽管如此,大多数代码只进行hasOwnProperty检查。

就像for,for-in如果异步函数中的工作需要串行完成,则它在异步函数中运行良好。

显示代码片段

  1. 显式使用迭代器(ES2015+)
    for-of隐式使用迭代器,为您完成所有 scut 工作。有时,您可能希望显式使用迭代器。它看起来像这样:

    const a = ["a", "b", "c"];
    const it = a.values(); // Or `const it = a[Symbol.iterator]();` if you like
    let entry;
    while (!(entry = it.next()).done) {
    console.log(entry.value);
    }

Related posts:

  1. JavaScript 技巧之 如果你不知道的console对象方法是相当惊人的
  2. Javascript问答之 JavaScript 闭包是如何工作的?
  3. Javascript问答之 如何在另一个 JavaScript 文件中包含一个 JavaScript 文件?
  4. Javascript问答之使用“let”和“var”有什么区别?

发表回复 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注

工具区

繁体中文

近期文章

  • Windows11教程大全之Windows 11到底是什么
  • Windows 11 的第一个大更新来了:2022年新增6大新功能
  • Chrome 控制台实用程序开发 之 09 monitor(function) 监视窗口对象上的所有调整大小事件
  • Chrome 控制台实用程序开发 之 08 keys(object) 监视窗口对象上的所有调整大小事件
  • Chrome 控制台实用程序开发 之 07 keys(object) 获取数组key值

近期评论

  1. J1o! - V2EX-Flutter 您应该选择哪个 IDE/编辑器?(Android Studio VS Code Intellij IDEA)发表在Flutter 您应该选择哪个IDE/编辑器?(Android Studio VS Code Intellij IDEA)
  2. 编程书籍推荐之《Think Like a Programmer: An Introduction to Creative Problem Solvin》 - AI编程自学网发表在如何解决任何编程问题

    推荐文章

    1. JavaScript 技巧之 如果你不知道的console对象方法是相当惊人的
    2. Javascript问答之 JavaScript 闭包是如何工作的?
    3. Javascript问答之 如何在另一个 JavaScript 文件中包含一个 JavaScript 文件?
    4. Javascript问答之使用“let”和“var”有什么区别?
    • 0经验开发
    • Access
    • adsense
    • Android
    • App开发赚钱
    • AWS云计算
    • Chrome
    • Chrome 控制台实用程序开发
    • CSS
    • CSS 基础教程
    • Flutter
    • Flutter基础
    • Flutter杂谈
    • HarmonyOS 鸿蒙
    • HarmonyOS基础
    • HTML
    • HTML基础
    • HTML技巧
    • JavaScript
    • JavaScript 基础
    • JavaScript 技巧
    • JavaScript 简介
    • JavaScript问答
    • oracle
    • oracle
    • pandas教程
    • PHP
    • PHP 杂谈
    • Python
    • Python实战
    • Python技巧
    • Python杂谈
    • SEO 技巧
    • Tiktok抖音小程序
    • UI设计
    • Web编程
    • Windows11
    • WordPress
    • WordPress 部署云主机VPS
    • WordPress 问答
    • WordPress 问答已解决
    • WordPress 问答未解决
    • WordPress使用技巧
    • WordPress插件
    • WordPress杂谈
    • WordPress盈利
    • Wordpress配置
    • WorPress建站技巧
    • 云服务推广
    • 云计算
    • 人工智能与机器学习
    • 低代码与无代码
    • 信息论基础
    • 元宇宙
    • 副业和涨工资
    • 副业技巧
    • 在线课程
    • 学习编程技巧
    • 小程序
    • 建站指南
    • 微服务架构
    • 微软
    • 思想类
    • 技术文章技巧
    • 技术潮流
    • 技能考试
    • 抖音小程序
    • 教育信息化
    • 数据库
    • 未分类
    • 程序员内功
    • 程序员装备
    • 经典书籍学习
    • 编程书籍推荐
    • 编程书籍推荐
    • 编程人生
    • 编程历史
    • 编程市场研究
    • 编程思想
    • 编程意义
    • 编程组件
    • 编程能力提高
    • 编程语言
    • 编程面试与工作
    • 腾讯云
    • 视频博主
    • 计算机科学中的数学
    • 读书笔记
    • 软件估价
    • 软考
    • 通识知识
    • 销售 API
    • 阿里云
    • 高级信息系统项目管理师
    • 高级系统架构设计师

    Discord JavaScript SpringBoot windows11 元宇宙 微服务 程序员内功 计算机视觉 问题未解决

    登录
    © 2022 AI编程自学网 | Powered by Minimalist Blog WordPress Theme