在 JavaScript 中循环(foreach)数组

发布于 2025-01-07 03:59:13 字数 36 浏览 1 评论 0 原文

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

How can I loop through all the entries in an array using JavaScript?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

旧时浪漫 2025-01-14 03:59:13

TL;DR

  • 您最好的选择通常是

    • for-of 循环(仅限 ES2015+;规范 | MDN< /a>) - 简单且异步友好
      for (theArray 的 const 元素) {
          // ...使用 `element`...
      }
      


    • forEach(仅限 ES5+;规范 | MDN)(或其亲属) some 等) - 异步友好(但请参阅详细信息)
      theArray.forEach(element => {
          // ...使用 `element`...
      });
      
    • 一个简单的老式 for 循环 - async - 友好
      for (let index = 0; index < theArray.length; ++index) {
          const 元素 = theArray[索引];
          // ...使用 `element`...
      }
      
    • (很少) for-in 有保护措施 - 异步友好
      for (const propertyName in theArray) {
          if (/*...是一个数组元素属性(见下文)...*/) {
              const 元素 = theArray[属性名称];
              // ...使用 `element`...
          }
      }
      
  • 一些快速的“不要”:

    • 不要使用for-in,除非您在使用时有防护措施,或者至少知道它为什么会咬您。
    • 如果不使用 map 的返回值,就不要使用它
      (遗憾的是有人在教 map< /code> [规范 / MDN] 就好像它是 forEach —但正如我在博客上写的那样,这不是它的用途。如果您不使用它创建的数组,请不要使用map。)
    • 如果回调执行异步工作并且您希望 forEach 等待该工作完成(因为它不会)。


但是还有很多更多内容需要探索,请继续阅读...


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

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

对于实际数组,

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

  1. 使用 for-of (隐式使用迭代器) (ES2015+)
  2. 使用 forEach 及相关(ES5+)
  3. 使用简单的 for 循环
  4. 使用 for-in 正确
  5. 显式使用迭代器 (ES2015+)

(您可以在此处查看那些旧规范: ES5ES2015,但两者均已被取代;当前编辑的草稿始终是 此处。)

详细信息:

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

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

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

没有比这更简单的了!在幕后,它从数组中获取迭代器并循环遍历迭代器返回的值。数组提供的迭代器按从开始到结束的顺序提供数组元素的值。

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

理论上,for-of 循环涉及多个函数调用(一个用于获取迭代器,然后一个用于从中获取每个值)。即使这是真的,也无需担心,在现代 JavaScript 引擎中,函数调用非常很便宜(它让我为 forEach [如下]感到困扰直到我研究它;详细信息)。但此外,在处理数组等内容的本机迭代器时,JavaScript 引擎会优化这些调用(在性能关键的代码中)。

for-of 完全是异步友好的。如果您需要串行(而不是并行)完成循环体中的工作,则循环体中的 await 将等待 Promise 解决后再继续。这是一个愚蠢的例子:

function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

async function showSlowly(messages) {
    for (const message of messages) {
        await delay(400);
        console.log(message);
    }
}

showSlowly([
    "So", "long", "and", "thanks", "for", "all", "the", "fish!"
]);
// `.catch` omitted because we know it never rejects

请注意单词在每个单词之前出现的时间是如何延迟的。

这是编码风格的问题,但是 for-of 是我在循环任何可迭代对象时首先要做的事情。

2. 使用 forEach 及相关内容

在任何可以访问 ES5 添加的 Array 功能的现代环境(因此,不是 IE8)中,您都可以使用 forEach (规范 |

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

forEach 接受一个回调函数,并且可以选择在调用该回调时用作 this 的值(上面未使用)。按顺序为数组中的每个元素调用回调,跳过稀疏数组中不存在的元素。虽然上面我只使用了一个参数,但回调函数是通过三个参数调用的:该迭代的元素、该元素的索引以及对要迭代的数组的引用(如果您的函数还没有它)便利)。

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

for-of不同,forEach的缺点是它不理解async函数和await。如果您使用 async 函数作为回调,forEach 不会等待该函数的 Promise 解决后再继续。这是来自 for-ofasync 示例,使用 forEach 代替 - 请注意初始延迟,但随后所有文本立即显示等待时间:

function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

async function showSlowly(messages) {
    // INCORRECT, doesn't wait before continuing,
    // doesn't handle promise rejections
    messages.forEach(async message => {
        await delay(400);
        console.log(message);
    });
}

showSlowly([
    "So", "long", "and", "thanks", "for", "all", "the", "fish!"
]);
// `.catch` omitted because we know it never rejects

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

  • every (规范 | href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/every" rel="noreferrer">MDN) - 回调第一次返回 false 时停止循环值
  • some (规范 | MDN) - 回调第一次返回 true 时停止循环值
  • 过滤器规范 | MDN) - 创建一个新数组,其中包含回调返回的元素一个真实值,忽略那些不
  • 映射的值(规格 | MDN) - 根据返回的值创建一个新数组通过回调
  • reduce (spec | MDN) - 通过重复调用回调来建立一个值,传入之前的值;有关详细信息,请参阅规范
  • reduceRight规范 | MDN) - 类似reduce,但按降序而不是升序工作

forEach 一样,如果您使用 async 函数作为回调,则这些都不会等待该函数承诺解决。这意味着:

  • 使用 async 函数回调永远不适合 everysomefilter 因为它们会处理返回的承诺就好像它是一个真实值一样;他们不会等待承诺解决然后使用履行价值。
  • 使用 async 函数回调通常适合 map如果目标是将某项数组转换为 Promise 数组,也许用于传递给 Promise 组合器函数之一(Promise.allPromise.racepromise.allSettled,或 < a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise/any" rel="noreferrer">Promise.any)。
  • 使用 async 函数回调很少适合于 reducereduceRight,因为(再次)回调将始终返回一个 Promise。但是有一种习惯用法是使用 reduce (const Promise = array.reduce((p, element) => p.then(/*. ..使用 `element`...*/));) 的东西,但通常在这些情况下 for-offor 循环位于 < code>async 函数会更清晰,更容易调试。

3. 使用简单的 for 循环

有时旧的方法是最好的:

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

如果数组的长度在循环期间不会改变,并且它是在对性能高度敏感的代码中,则预先获取长度的稍微复杂的版本可能是一个微小 快一点:

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

和/或倒数:

const a = ["a", "b", "c"];
for (let index = a.length - 1; index >= 0; --index) {
    const element = a[index];
    console.log(element);
}

但对于现代 JavaScript 引擎,您很少需要竭尽全力。

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

// (The `NodeList` from `querySelectorAll` is array-like)
const divs = document.querySelectorAll("div");
for (let index = 0; index < divs.length; ++index) {
    divs[index].addEventListener('click', e => {
        console.log("Index is: " + index);
    });
}
<div>zero</div>
<div>one</div>
<div>two</div>
<div>three</div>
<div>four</div>

在上面,如果单击第一个,您将得到“Index is: 0”,如果单击最后一个,您将得到“Index is: 4”。如果您使用 var 而不是 let,这不起作用(您总是会看到“Index is: 5”)。

for-of 一样,for 循环在 async 函数中运行良好。下面是之前使用 for 循环的示例:

function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

async function showSlowly(messages) {
    for (let i = 0; i < messages.length; ++i) {
        const message = messages[i];
        await delay(400);
        console.log(message);
    }
}

showSlowly([
    "So", "long", "and", "thanks", "for", "all", "the", "fish!"
]);
// `.catch` omitted because we know it never rejects

4. 正确使用for-in

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

数组上 for-in 的唯一实际用例是

  • :一个 < 一个href="https://en.wikipedia.org/wiki/Sparse_array" rel="noreferrer">稀疏数组,其中有大量间隙,或者
  • 您在数组对象上使用非元素属性,并且希望将它们包含在循环中

仅查看第一个示例:如果您使用适当的保障措施:

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

请注意这三项检查:

  1. 该对象是否拥有该名称的自己属性(不是从其原型继承的属性;此检查通常也写为 a.hasOwnProperty(name) 但 ES2022 添加了 Object.hasOwn 更可靠),以及

  2. 名称全部是十进制数字(例如,正常字符串形式,而不是科学记数法),并且

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

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

当然,在内联代码中您不会这样做。您将编写一个实用函数。也许:

// Utility function for antiquated environments without `forEach`
const hasOwn = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);
const rexNum = /^0$|^[1-9]\d*$/;
function sparseEach(array, callback, thisArg) {
    for (const name in array) {
        const index = +name;
        if (hasOwn(a, name) &&
            rexNum.test(name) &&
            index <= 4294967294
           ) {
            callback.call(thisArg, array[name], index, array);
        }
    }
}

const a = [];
a[5] = "five";
a[10] = "ten";
a[100000] = "one hundred thousand";
a.b = "bee";

sparseEach(a, (value, index) => {
    console.log("Value at " + index + " is " + value);
});

for 类似,如果其中的工作需要串行完成,for-in 在异步函数中效果很好。

function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

async function showSlowly(messages) {
    for (const name in messages) {
        if (messages.hasOwnProperty(name)) { // Almost always this is the only check people do
            const message = messages[name];
            await delay(400);
            console.log(message);
        }
    }
}

showSlowly([
    "So", "long", "and", "thanks", "for", "all", "the", "fish!"
]);
// `.catch` omitted because we know it never rejects

5. 显式使用迭代器 (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) {
    const element = entry.value;
    console.log(element);
}

迭代器是与规范中的迭代器定义相匹配的对象。每次调用它的 next 方法时都会返回一个新的结果对象。结果对象有一个属性done,告诉我们它是否完成,还有一个属性value,其中包含该迭代的值。 如果donefalse,则done是可选的;如果valueundefined,则为可选。)

( get for value 因迭代器而异。对于数组,默认迭代器提供每个数组元素的值(示例中的 "a""b""c"较早)。数组还有其他三个返回迭代器的方法:

  • values():这是返回默认迭代器的 [Symbol.iterator] 方法的别名。
  • keys():返回提供数组中每个键(索引)的迭代器。在上面的示例中,它将提供 0,然后是 1,然后是 2(作为数字,而不是字符串)。 (另请注意,在稀疏数组中,它 包含不存在的元素的索引。)
  • entries():返回一个提供[key, value] 数组。

由于迭代器对象在调用 next 之前不会前进,因此它们在 async 函数循环中运行良好。下面是之前显式使用迭代器的 for-of 示例:

function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

async function showSlowly(messages) {
    const it = messages.values()
    while (!(entry = it.next()).done) {
        await delay(400);
        const element = entry.value;
        console.log(element);
    }
}

showSlowly([
    "So", "long", "and", "thanks", "for", "all", "the", "fish!"
]);
// `.catch` omitted because we know it never rejects

对于类似数组的对象

除了真正的数组之外,还有一些类似数组的对象,它们具有 length 属性和具有全数字名称的属性:NodeList 实例HTMLCollection 实例arguments 对象等。我们如何循环访问它们的内容?

使用上面的大多数选项

上面的数组方法中至少有一些,可能是大多数甚至全部都同样适用于类似数组的对象:

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

    for-of 使用迭代器 由对象提供(如果有)。这包括主机提供的对象(例如 DOM 集合和列表)。例如,来自 getElementsByXYZ 方法的 HTMLCollection 实例和来自 querySelectorAllNodeList 实例都支持迭代。 (这是由 HTML 和 DOM 规范相当巧妙地定义的。基本上,任何具有长度和索引访问的对象都是自动可迭代的。它 > 必须标记为 iterable;仅用于除了可迭代之外还支持 forEachvalues 的集合键entries 方法没有;HTMLCollection 没有,但两者都是可迭代的。)

    下面是循环 div 元素的示例:

const divs = document.querySelectorAll("div");
for (const div of divs) {
    div.textContent = Math.random();
}
<div>zero</div>
<div>one</div>
<div>two</div>
<div>three</div>
<div>four</div>

  1. 使用 forEach 及相关 (ES5+)

    Array.prototype 上的各种函数都是“有意通用的”,可以通过 Function#call (规范 | MDN) 或 Function#apply (规范 | MDN)。 (如果您必须处理 IE8 或更早版本 [哎哟],请参阅本答案末尾的“主机提供的对象的警告”,但这对于模糊现代的浏览器来说不是问题。)

    假设您想在 NodechildNodes 集合(它是一个 HTMLCollection)上使用 forEach ,本身没有 forEach )。你会这样做:

    Array.prototype.forEach.call(node.childNodes, (child) => {
        // 对 `child` 做一些事情
    });
    

    (但请注意,您可以在 node.childNodes 上使用 for-of。)

    如果您要经常这样做,您可能需要将函数引用的副本获取到变量中以供重用,例如:

    //(这大概都在模块或某些作用域函数中)
    const forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
    
    // 然后稍后...
    forEach(node.childNodes, (child) => {
        // 对 `child` 做一些事情
    });
    
  2. 使用简单的for循环

    也许显然,一个简单的 for 循环适用于类似数组的对象。

  3. 显式使用迭代器 (ES2015+)

    参见#1。

也许可以通过for-in(有保障措施)逃脱惩罚,但是有了所有这些更合适的选项,没有理由尝试。

创建真正的数组

有时,您可能希望将类似数组的对象转换为真正的数组。做到这一点非常简单:

  1. 使用 Array.from

    Array.from (规范) | (MDN)(ES2015+,但很容易填充)创建来自类数组对象的数组,可以选择首先通过映射函数传递条目。所以:

    const divs = Array.from(document.querySelectorAll("div"));
    

    ...从 querySelectorAll 获取 NodeList 并从中创建一个数组。

    如果您要以某种方式映射内容,映射功能会很方便。例如,如果您想获取具有给定类的元素的标签名称数组:

    // 典型用法(带有箭头函数):
    const divs = Array.from(document.querySelectorAll(".some-class"), element => element.tagName);
    
    // 传统函数(因为 `Array.from` 可以被填充):
    var divs = Array.from(document.querySelectorAll(".some-class"), function(element) {
        返回元素.tagName;
    });
    
  2. 使用扩展语法 (...)

    也可以使用 ES2015 的扩展语法。与 for-of 一样,它使用 迭代器 由对象提供(请参阅上一节中的 #1):

    const trueArray = [...iterableObject];
    

    例如,如果我们想将 NodeList 转换为真正的数组,使用扩展语法,这会变得非常简洁:

    const divs = [...document.querySelectorAll("div")];
    
  3. <强>使用数组的slice方法

    我们可以使用 slice 方法数组,与上面提到的其他方法一样,它是“有意通用的”,因此可以与类似数组的对象一起使用,如下所示:

    const trueArray = Array.prototype.slice.call(arrayLikeObject);
    

    例如,如果我们想将 NodeList 转换为真正的数组,我们可以这样做:

    const divs = Array.prototype.slice.call(document.querySelectorAll("div"));
    

    (如果您仍然需要处理 IE8 [哎哟],将会失败;IE8 不允许您像这样使用主机提供的对象作为 this。)

> this 喜欢

如果使用 array.protype 使用主机提供的 array类似阵列的对象(例如,dom dom)收藏品以及此类浏览器而不是JavaScript引擎),像IE8这样的过时的浏览器不一定会处理这种方式,因此,如果您必须支持它们,请确保在目标环境中测试。但这不是现代浏览器的问题。 (对于非浏览器环境,自然会取决于环境。)

TL;DR

  • Your best bets are usually

    • a for-of loop (ES2015+ only; spec | MDN) - simple and async-friendly
      for (const element of theArray) {
          // ...use `element`...
      }
      
    • forEach (ES5+ only; spec | MDN) (or its relatives some and such) - not async-friendly (but see details)
      theArray.forEach(element => {
          // ...use `element`...
      });
      
    • a simple old-fashioned for loop - async-friendly
      for (let index = 0; index < theArray.length; ++index) {
          const element = theArray[index];
          // ...use `element`...
      }
      
    • (rarely) for-in with safeguards - async-friendly
      for (const propertyName in theArray) {
          if (/*...is an array element property (see below)...*/) {
              const element = theArray[propertyName];
              // ...use `element`...
          }
      }
      
  • Some quick "don't"s:

    • Don't use for-in unless you use it with safeguards or are at least aware of why it might bite you.
    • Don't use map if you're not using its return value.
      (There's sadly someone out there teaching map [spec / MDN] as though it were forEach — but as I write on my blog, that's not what it's for. If you aren't using the array it creates, don't use map.)
    • Don't use forEach if the callback does asynchronous work and you want the forEach to wait until that work is done (because it won't).

But there's lots more to explore, read on...


JavaScript has powerful semantics for looping through arrays and array-like objects. I've split the answer into two parts: Options for genuine arrays, and options for things that are just array-like, such as the arguments object, other iterable objects (ES2015+), DOM collections, and so on.

Okay, let's look at our options:

For Actual Arrays

You have five options (two supported basically forever, another added by ECMAScript 5 ["ES5"], and two more added in ECMAScript 2015 ("ES2015", aka "ES6"):

  1. Use for-of (use an iterator implicitly) (ES2015+)
  2. Use forEach and related (ES5+)
  3. Use a simple for loop
  4. Use for-in correctly
  5. Use an iterator explicitly (ES2015+)

(You can see those old specs here: ES5, ES2015, but both have been superceded; the current editor's draft is always here.)

Details:

1. Use for-of (use an iterator implicitly) (ES2015+)

ES2015 added iterators and iterables to JavaScript. Arrays are iterable (so are strings, Maps, and Sets, as well as DOM collections and lists, as you'll see later). Iterable objects provide iterators for their values. The new for-of statement loops through the values returned by an iterator:

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

It doesn't get simpler than that! Under the covers, that gets an iterator from the array and loops through the values the iterator returns. The iterator provided by arrays provides the values of the array elements, in order beginning to end.

Notice how element is scoped to each loop iteration; trying to use element after the end of the loop would fail because it doesn't exist outside the loop body.

In theory, a for-of loop involves several function calls (one to get the iterator, then one to get each value from it). Even when that's true, it's nothing to worry about, function calls are very cheap in modern JavaScript engines (it bothered me for forEach [below] until I looked into it; details). But additionally, JavaScript engines optimize those calls away (in performance-critical code) when dealing with native iterators for things like arrays.

for-of is entirely async-friendly. If you need the work in a loop body to be done in series (not in parallel), an await in the loop body will wait for the promise to settle before continuing. Here's a silly example:

function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

async function showSlowly(messages) {
    for (const message of messages) {
        await delay(400);
        console.log(message);
    }
}

showSlowly([
    "So", "long", "and", "thanks", "for", "all", "the", "fish!"
]);
// `.catch` omitted because we know it never rejects

Note how the words appear with a delay before each one.

It's a matter of coding style, but for-of is the first thing I reach for when looping through anything iterable.

2. Use forEach and related

In any even vaguely-modern environment (so, not IE8) where you have access to the Array features added by ES5, you can use forEach (spec | MDN) if you're only dealing with synchronous code (or you don't need to wait for an asynchronous process to finish during the loop):

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

forEach accepts a callback function and, optionally, a value to use as this when calling that callback (not used above). The callback is called for each element in the array, in order, skipping non-existent elements in sparse arrays. Although I only used one parameter above, the callback is called with three arguments: The element for that iteration, the index of that element, and a reference to the array you're iterating over (in case your function doesn't already have it handy).

Like for-of, forEach has the advantage that you don't have to declare indexing and value variables in the containing scope; in this case, they're supplied as arguments to the iteration function, and so nicely scoped to just that iteration.

Unlike for-of, forEach has the disadvantage that it doesn't understand async functions and await. If you use an async function as the callback, forEach does not wait for that function's promise to settle before continuing. Here's the async example from for-of using forEach instead — notice how there's an initial delay, but then all the text appears right away instead of waiting:

function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

async function showSlowly(messages) {
    // INCORRECT, doesn't wait before continuing,
    // doesn't handle promise rejections
    messages.forEach(async message => {
        await delay(400);
        console.log(message);
    });
}

showSlowly([
    "So", "long", "and", "thanks", "for", "all", "the", "fish!"
]);
// `.catch` omitted because we know it never rejects

forEach is the "loop through them all" function, but ES5 defined several other useful "work your way through the array and do things" functions, including:

  • every (spec | MDN) - stops looping the first time the callback returns a falsy value
  • some (spec | MDN) - stops looping the first time the callback returns a truthy value
  • filter (spec | MDN) - creates a new array including elements where the callback returns a truthy value, omitting the ones where it doesn't
  • map (spec | MDN) - creates a new array from the values returned by the callback
  • reduce (spec | MDN) - builds up a value by repeatedly calling the callback, passing in previous values; see the spec for the details
  • reduceRight (spec | MDN) - like reduce, but works in descending rather than ascending order

As with forEach, if you use an async function as your callback, none of those waits for the function's promise to settle. That means:

  • Using an async function callback is never appropriate with every, some, and filter since they will treat the returned promise as though it were a truthy value; they don't wait for the promise to settle and then use the fulfillment value.
  • Using an async function callback is often appropriate with map, if the goal is to turn an array of something into an array of promises, perhaps for passing to one of the promise combinator functions (Promise.all, Promise.race, promise.allSettled, or Promise.any).
  • Using an async function callback is rarely appropriate with reduce or reduceRight, because (again) the callback will always return a promise. But there is an idiom of building a chain of promises from an array that uses reduce (const promise = array.reduce((p, element) => p.then(/*...something using `element`...*/));), but usually in those cases a for-of or for loop in an async function will be clearer and easier to debug.

3. Use a simple for loop

Sometimes the old ways are the best:

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

If the length of the array won't change during the loop, and it's in highly performance-sensitive code, a slightly more complicated version grabbing the length up front might be a tiny bit faster:

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

And/or counting backward:

const a = ["a", "b", "c"];
for (let index = a.length - 1; index >= 0; --index) {
    const element = a[index];
    console.log(element);
}

But with modern JavaScript engines, it's rare you need to eke out that last bit of juice.

Before ES2015, the loop variable had to exist in the containing scope, because var only has function-level scope, not block-level scope. But as you saw in the examples above, you can use let within the for to scope the variables to just the loop. And when you do that, the index variable is recreated for each loop iteration, meaning closures created in the loop body keep a reference to the index for that specific iteration, which solves the old "closures in loops" problem:

// (The `NodeList` from `querySelectorAll` is array-like)
const divs = document.querySelectorAll("div");
for (let index = 0; index < divs.length; ++index) {
    divs[index].addEventListener('click', e => {
        console.log("Index is: " + index);
    });
}
<div>zero</div>
<div>one</div>
<div>two</div>
<div>three</div>
<div>four</div>

In the above, you get "Index is: 0" if you click the first and "Index is: 4" if you click the last. This does not work if you use var instead of let (you'd always see "Index is: 5").

Like for-of, for loops work well in async functions. Here's the earlier example using a for loop:

function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

async function showSlowly(messages) {
    for (let i = 0; i < messages.length; ++i) {
        const message = messages[i];
        await delay(400);
        console.log(message);
    }
}

showSlowly([
    "So", "long", "and", "thanks", "for", "all", "the", "fish!"
]);
// `.catch` omitted because we know it never rejects

4. Use for-in correctly

for-in isn't for looping through arrays, it's for looping through the names of an object's properties. It does often seem to work for looping through arrays as a by-product of the fact that arrays are objects, but it doesn't just loop through the array indexes, it loops through all enumerable properties of the object (including inherited ones). (It also used to be that the order wasn't specified; it is now [details in this other answer], but even though the order is specified now, the rules are complex, there are exceptions, and relying on the order is not best practice.)

The only real use cases for for-in on an array are:

  • It's a sparse array with massive gaps in it, or
  • You're using non-element properties on the array object and you want to include them in the loop

Looking only at that first example: You can use for-in to visit those sparse array elements if you use appropriate safeguards:

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

Note the three checks:

  1. That the object has its own property by that name (not one it inherits from its prototype; this check is also often written as a.hasOwnProperty(name) but ES2022 adds Object.hasOwn which can be more reliable), and

  2. That the name is all decimal digits (e.g., normal string form, not scientific notation), and

  3. That the name's value when coerced to a number is <= 2^32 - 2 (which is 4,294,967,294). Where does that number come from? It's part of the definition of an array index in the specification. Other numbers (non-integers, negative numbers, numbers greater than 2^32 - 2) are not array indexes. The reason it's 2^32 - 2 is that that makes the greatest index value one lower than 2^32 - 1, which is the maximum value an array's length can have. (E.g., an array's length fits in a 32-bit unsigned integer.)

...although with that said, most code only does the hasOwnProperty check.

You wouldn't do that in inline code, of course. You'd write a utility function. Perhaps:

// Utility function for antiquated environments without `forEach`
const hasOwn = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);
const rexNum = /^0$|^[1-9]\d*$/;
function sparseEach(array, callback, thisArg) {
    for (const name in array) {
        const index = +name;
        if (hasOwn(a, name) &&
            rexNum.test(name) &&
            index <= 4294967294
           ) {
            callback.call(thisArg, array[name], index, array);
        }
    }
}

const a = [];
a[5] = "five";
a[10] = "ten";
a[100000] = "one hundred thousand";
a.b = "bee";

sparseEach(a, (value, index) => {
    console.log("Value at " + index + " is " + value);
});

Like for, for-in works well in asynchronous functions if the work within it needs to be done in series.

function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

async function showSlowly(messages) {
    for (const name in messages) {
        if (messages.hasOwnProperty(name)) { // Almost always this is the only check people do
            const message = messages[name];
            await delay(400);
            console.log(message);
        }
    }
}

showSlowly([
    "So", "long", "and", "thanks", "for", "all", "the", "fish!"
]);
// `.catch` omitted because we know it never rejects

5. Use an iterator explicitly (ES2015+)

for-of uses an iterator implicitly, doing all the scut work for you. Sometimes, you might want to use an iterator explicitly. It looks like this:

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) {
    const element = entry.value;
    console.log(element);
}

An iterator is an object matching the Iterator definition in the specification. Its next method returns a new result object each time you call it. The result object has a property, done, telling us whether it's done, and a property value with the value for that iteration. (done is optional if it would be false, value is optional if it would be undefined.)

What you get for value varies depending on the iterator. On arrays, the default iterator provides the value of each array element ("a", "b", and "c" in the example earlier). Arrays also have three other methods that return iterators:

  • values(): This is an alias for the [Symbol.iterator] method that returns the default iterator.
  • keys(): Returns an iterator that provides each key (index) in the array. In the example above, it would provide 0, then 1, then 2 (as numbers, not strings). (Also note that in a sparse array, it will include indexes for elements that don't exist.)
  • entries(): Returns an iterator that provides [key, value] arrays.

Since iterator objects don't advance until you call next, they work well in async function loops. Here's the earlier for-of example using the iterator explicitly:

function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

async function showSlowly(messages) {
    const it = messages.values()
    while (!(entry = it.next()).done) {
        await delay(400);
        const element = entry.value;
        console.log(element);
    }
}

showSlowly([
    "So", "long", "and", "thanks", "for", "all", "the", "fish!"
]);
// `.catch` omitted because we know it never rejects

For Array-Like Objects

Aside from true arrays, there are also array-like objects that have a length property and properties with all-digits names: NodeList instances, HTMLCollection instances, the arguments object, etc. How do we loop through their contents?

Use most of the options above

At least some, and possibly most or even all, of the array approaches above apply equally well to array-like objects:

  1. Use for-of (use an iterator implicitly) (ES2015+)

    for-of uses the iterator provided by the object (if any). That includes host-provided objects (like DOM collections and lists). For instance, HTMLCollection instances from getElementsByXYZ methods and NodeLists instances from querySelectorAll both support iteration. (This is defined quite subtly by the HTML and DOM specifications. Basically, any object with length and indexed access is automatically iterable. It doesn't have to be marked iterable; that is used only for collections that, in addition to being iterable, support forEach, values, keys, and entries methods. NodeList does; HTMLCollection doesn't, but both are iterable.)

    Here's an example of looping through div elements:

const divs = document.querySelectorAll("div");
for (const div of divs) {
    div.textContent = Math.random();
}
<div>zero</div>
<div>one</div>
<div>two</div>
<div>three</div>
<div>four</div>

  1. Use forEach and related (ES5+)

    The various functions on Array.prototype are "intentionally generic" and can be used on array-like objects via Function#call (spec | MDN) or Function#apply (spec | MDN). (If you have to deal with IE8 or earlier [ouch], see the "Caveat for host-provided objects" at the end of this answer, but it's not an issue with vaguely-modern browsers.)

    Suppose you wanted to use forEach on a Node's childNodes collection (which, being an HTMLCollection, doesn't have forEach natively). You'd do this:

    Array.prototype.forEach.call(node.childNodes, (child) => {
        // Do something with `child`
    });
    

    (Note, though, that you could just use for-of on node.childNodes.)

    If you're going to do that a lot, you might want to grab a copy of the function reference into a variable for reuse, e.g.:

    // (This is all presumably in a module or some scoping function)
    const forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
    
    // Then later...
    forEach(node.childNodes, (child) => {
        // Do something with `child`
    });
    
  2. Use a simple for loop

    Perhaps obviously, a simple for loop works for array-like objects.

  3. Use an iterator explicitly (ES2015+)

    See #1.

You may be able to get away with for-in (with safeguards), but with all of these more appropriate options, there's no reason to try.

Create a true array

Other times, you may want to convert an array-like object into a true array. Doing that is surprisingly easy:

  1. Use Array.from

    Array.from (spec) | (MDN) (ES2015+, but easily polyfilled) creates an array from an array-like object, optionally passing the entries through a mapping function first. So:

    const divs = Array.from(document.querySelectorAll("div"));
    

    ...takes the NodeList from querySelectorAll and makes an array from it.

    The mapping function is handy if you were going to map the contents in some way. For instance, if you wanted to get an array of the tag names of the elements with a given class:

    // Typical use (with an arrow function):
    const divs = Array.from(document.querySelectorAll(".some-class"), element => element.tagName);
    
    // Traditional function (since `Array.from` can be polyfilled):
    var divs = Array.from(document.querySelectorAll(".some-class"), function(element) {
        return element.tagName;
    });
    
  2. Use spread syntax (...)

    It's also possible to use ES2015's spread syntax. Like for-of, this uses the iterator provided by the object (see #1 in the previous section):

    const trueArray = [...iterableObject];
    

    So for instance, if we want to convert a NodeList into a true array, with spread syntax this becomes quite succinct:

    const divs = [...document.querySelectorAll("div")];
    
  3. Use the slice method of arrays

    We can use the slice method of arrays, which like the other methods mentioned above is "intentionally generic" and so can be used with array-like objects, like this:

    const trueArray = Array.prototype.slice.call(arrayLikeObject);
    

    So for instance, if we want to convert a NodeList into a true array, we could do this:

    const divs = Array.prototype.slice.call(document.querySelectorAll("div"));
    

    (If you still have to handle IE8 [ouch], will fail; IE8 didn't let you use host-provided objects as this like that.)

Caveat for host-provided objects

If you use Array.prototype functions with host-provided array-like objects (for example, DOM collections and such provided by the browser rather than the JavaScript engine), obsolete browsers like IE8 didn't necessarily handle that way, so if you have to support them, be sure to test in your target environments. But it's not an issue with vaguely-modern browsers. (For non-browser environments, naturally it'll depend on the environment.)

说好的呢 2025-01-14 03:59:13

注意:这个答案已经过时了。如需更现代的方法,请查看数组。感兴趣的方法可能是:

  • forEach
  • 地图
  • 过滤器
  • zip
  • 减少
  • 一些

JavaScript 是一个普通的 for 循环:

var length = arr.length,
    element = null;
for (var i = 0; i < length; i++) {
  element = arr[i];
  // Do something with element
}

但是请注意,只有当您有一个密集数组并且每个索引都被一个元素占用时,这种方法才有效。如果数组是稀疏的,那么使用这种方法可能会遇到性能问题,因为您将迭代数组中实际上不存在的大量索引。在这种情况下,for .. in 循环可能是一个更好的主意。 但是,您必须使用适当的保护措施来确保仅对数组的所需属性(即数组元素)进行操作,因为 for..in -loop 也将在旧版浏览器中被枚举,或者如果附加属性被定义为可枚举

ECMAScript 5 中,数组原型上会有一个 forEach 方法,但它是旧版浏览器不支持。因此,为了能够一致地使用它,您必须拥有支持它的环境(例如,Node.js)。 js 用于服务器端 JavaScript),或使用“Polyfill”。然而,用于此功能的 Polyfill 很简单,并且由于它使代码更易于阅读,因此它是一个很好的 Polyfill。

Note: This answer is hopelessly out-of-date. For a more modern approach, look at the methods available on an array. Methods of interest might be:

  • forEach
  • map
  • filter
  • zip
  • reduce
  • every
  • some

The standard way to iterate an array in JavaScript is a vanilla for-loop:

var length = arr.length,
    element = null;
for (var i = 0; i < length; i++) {
  element = arr[i];
  // Do something with element
}

Note, however, that this approach is only good if you have a dense array, and each index is occupied by an element. If the array is sparse, then you can run into performance problems with this approach, since you will iterate over a lot of indices that do not really exist in the array. In this case, a for .. in-loop might be a better idea. However, you must use the appropriate safeguards to ensure that only the desired properties of the array (that is, the array elements) are acted upon, since the for..in-loop will also be enumerated in legacy browsers, or if the additional properties are defined as enumerable.

In ECMAScript 5 there will be a forEach method on the array prototype, but it is not supported in legacy browsers. So to be able to use it consistently you must either have an environment that supports it (for example, Node.js for server side JavaScript), or use a "Polyfill". The Polyfill for this functionality is, however, trivial and since it makes the code easier to read, it is a good polyfill to include.

迟月 2025-01-14 03:59:13

如果您使用 jQuery 库,则可以使用 jQuery.each:

$.each(yourArray, function(index, value) {
  // do your stuff here
});

编辑:

根据问题,用户需要代码在 javascript 而不是 jquery 中,所以编辑是

var length = yourArray.length;   
for (var i = 0; i < length; i++) {
  // Do something with yourArray[i].
}

If you’re using the jQuery library, you can use jQuery.each:

$.each(yourArray, function(index, value) {
  // do your stuff here
});

EDIT :

As per question, user want code in javascript instead of jquery so the edit is

var length = yourArray.length;   
for (var i = 0; i < length; i++) {
  // Do something with yourArray[i].
}
゛清羽墨安 2025-01-14 03:59:13

向后循环

我认为 反向 for 循环值得在这里提及:

for (var i = array.length; i--; ) {
     // process array[i]
}

优点:

  • 您不需要声明临时 len 变量,或与 array.length< 进行比较/code> 每次迭代,其中任何一个都可能是微小的优化。
  • 以相反的顺序从 DOM 中删除同级通常更有效。 (浏览器需要减少其内部数组中元素的移动。)
  • 如果您在循环时修改数组,则在索引i处或之后(例如,您删除或插入array[i] 处的项目),然后前向循环将跳过向左移动到位置 i 的项目,或重新处理 i > 右移的第一项。在传统的 for 循环中,您可以更新i以指向需要处理的下一个项目 - 1,但简单地反转迭代方向通常更简单更优雅的解决方案
  • 同样,当修改或删除嵌套 DOM 元素时,反向处理可以避免错误。例如,考虑在处理子节点之前修改父节点的innerHTML。当到达子节点时,它将与 DOM 分离,并在写入父节点的 innerHTML 时被新创建的子节点替换。
  • 与其他一些可用选项相比,它的输入和阅读时间更短。虽然它输给了 forEach() 和 ES6 的 for ... of

缺点:

  • 它以相反的顺序处理项目。如果您要根据结果构建新数组,或者在屏幕上打印内容,自然输出将相对于原始顺序反转
  • 重复将同级作为第一个子级插入到 DOM 中以保留其顺序效率较低。 (浏览器必须不断地向右移动。)要高效且按顺序创建 DOM 节点,只需向前循环并正常追加(并且还使用“文档片段”)。
  • 对于初级开发人员来说,反向循环是令人困惑的。 (您可能会认为这是一个优势,具体取决于您的观点。)

我应该始终使用它吗?

一些开发人员默认使用反向 for 循环,除非有充分的理由向前循环。

虽然性能提升通常微不足道,但它有点令人尖叫:

“只需​​对列表中的每个项目执行此操作即可,我不关心顺序!”

然而在实践中,这实际上不是可靠的意图指示,因为它与您确实关心订单的情况没有区别,并且确实需要反向循环。因此,实际上需要另一个构造来准确表达“不关心”的意图,目前大多数语言(包括 ECMAScript)都无法实现这一点,但可以调用它,例如 forEachUnordered()

如果顺序并不重要,并且需要考虑效率(在游戏或动画引擎的最内层循环中),那么使用反向 for 循环作为首选模式可能是可以接受的。请记住,在现有代码中看到反向 for 循环并不一定意味着顺序无关!

最好使用 forEach()

一般来说,对于更高级别的代码,其中清晰度和安全性更受关注,我之前建议使用 Array::forEach 作为循环的默认模式(尽管现在我更喜欢使用for..of)。优先使用 forEach 而不是反向循环的原因是:

  • 读起来更清晰。
  • 它表明 i 不会在块内移动(这总是可能隐藏在长 forwhile 循环中的惊喜)。
  • 它为您提供了一个自由的关闭范围。
  • 它减少了局部变量的泄漏以及与外部变量的意外冲突(和突变)。

然后,当您在代码中看到反向 for 循环时,这暗示它是有充分理由被反转的(可能是上述原因之一)。看到传统的前向循环可能表明可以发生移位。

(如果意图的讨论对您来说毫无意义,那么您和您的代码可能会受益于观看 Crockford 的讲座 编程风格和你的大脑。)

现在使用 for..of 甚至更好!

关于 for..of 还是 forEach() 哪个更可取存在争议:

  • 为了获得最大的浏览器支持,for..of迭代器需要一个polyfill,使您的应用执行速度稍微慢一些要下载更大的文件。

  • 出于这个原因(并鼓励使用 mapfilter),一些前端样式指南完全禁止 for..of

  • 但上述问题不适用于 Node.js 应用程序,其中 for..of 现在得到了很好的支持。

  • 此外 await forEach 中不起作用 ()。使用 for..of最清晰的模式 在这种情况下。

就我个人而言,我倾向于使用看起来最容易阅读的内容,除非性能或缩小已成为主要问题。所以这些天我更喜欢使用 for..of 而不是 forEach(),但我总是会使用 mapfilter< /code> 或 查找some 时适用的。
(为了同事的利益,我很少使用 减少。)


它是如何工作的?

for (var i = 0; i < array.length; i++) { ... }   // Forwards

for (var i = array.length; i--; )    { ... }   // Reverse

您会注意到 i-- 是中间子句(我们通常在其中看到比较),最后一个子句为空(我们通常在其中看到 i++)。这意味着 i-- 也用作继续的条件。至关重要的是,它在每次迭代之前执行和检查。

  • 它如何从array.length开始而不爆炸?

    因为 i-- 在每次迭代之前运行,所以在第一次迭代时,我们实际上将访问 array.length - 1 处的项目这避免了 Array-out-of-bounds undefined 项的任何问题。

  • 为什么它在索引 0 之前不停止迭代?

    当条件 i-- 计算结果为假值时(当它产生 0 时),循环将停止迭代。

    诀窍在于,与 --i 不同,尾随的 i-- 运算符会递减 i 但产生值 在减量之前。您的控制台可以演示这一点:

    <代码>>变量我 = 5; [i,i--,i];

    <代码>[5,5,4]

    因此,在最后一次迭代中,i 之前为 1i-- 表达式将其更改为 0 > 但实际上产生 1 (真值),因此条件通过。在下一次迭代中,i--i更改为-1,但产生0(错误),导致执行立即从循环底部掉出。

    在传统的前向 for 循环中,i++++i 是可以互换的(正如 Douglas Crockford 指出的那样)。然而,在反向 for 循环中,因为我们的减量也是我们的条件表达式,所以如果我们想要处理索引 0 处的项目,我们必须坚持使用 i--


琐事

有些人喜欢画一个小箭头在反向 for 循环中,并以眨眼结束:

for (var i = array.length; i --> 0 ;) {

感谢 WYL 向我展示了反向 for 循环的优点和缺点。

Loop backwards

I think the reverse for loop deserves a mention here:

for (var i = array.length; i--; ) {
     // process array[i]
}

Advantages:

  • You do not need to declare a temporary len variable, or compare against array.length on each iteration, either of which might be a minute optimisation.
  • Removing siblings from the DOM in reverse order is usually more efficient. (The browser needs to do less shifting of elements in its internal arrays.)
  • If you modify the array while looping, at or after index i (for example you remove or insert an item at array[i]), then a forward loop would skip the item that shifted left into position i, or re-process the ith item that was shifted right. In a traditional for loop, you could update i to point to the next item that needs processing - 1, but simply reversing the direction of iteration is often a simpler and more elegant solution.
  • Similarly, when modifying or removing nested DOM elements, processing in reverse can circumvent errors. For example, consider modifying the innerHTML of a parent node before handling its children. By the time the child node is reached it will be detached from the DOM, having been replaced by a newly created child when the parent's innerHTML was written.
  • It is shorter to type, and read, than some of the other options available. Although it loses to forEach() and to ES6's for ... of.

Disadvantages:

  • It processes the items in reverse order. If you were building a new array from the results, or printing things on screen, naturally the output will be reversed with respect to the original order.
  • Repeatedly inserting siblings into the DOM as a first child in order to retain their order is less efficient. (The browser would keep having to shift things right.) To create DOM nodes efficiently and in order, just loop forwards and append as normal (and also use a "document fragment").
  • The reverse loop is confusing to junior developers. (You may consider that an advantage, depending on your outlook.)

Should I always use it?

Some developers use the reverse for loop by default, unless there is a good reason to loop forwards.

Although the performance gains are usually insignificant, it sort of screams:

"Just do this to every item in the list, I don't care about the order!"

However in practice that is not actually a reliable indication of intent, since it is indistinguishable from those occasions when you do care about the order, and really do need to loop in reverse. So in fact another construct would be needed to accurately express the "don't care" intent, something currently unavailable in most languages, including ECMAScript, but which could be called, for example, forEachUnordered().

If order doesn't matter, and efficiency is a concern (in the innermost loop of a game or animation engine), then it may be acceptable to use the reverse for loop as your go-to pattern. Just remember that seeing a reverse for loop in existing code does not necessarily mean that the order irrelevant!

It was better to use forEach()

In general for higher level code where clarity and safety are greater concerns, I previously recommended using Array::forEach as your default pattern for looping (although these days I prefer to use for..of). Reasons to prefer forEach over a reverse loop are:

  • It is clearer to read.
  • It indicates that i is not going to be shifted within the block (which is always a possible surprise hiding in long for and while loops).
  • It gives you a free scope for closures.
  • It reduces leakage of local variables and accidental collision with (and mutation of) outer variables.

Then when you do see the reverse for loop in your code, that is a hint that it is reversed for a good reason (perhaps one of the reasons described above). And seeing a traditional forward for loop may indicate that shifting can take place.

(If the discussion of intent makes no sense to you, then you and your code may benefit from watching Crockford's lecture on Programming Style & Your Brain.)

It is now even better to use for..of!

There is a debate about whether for..of or forEach() are preferable:

  • For maximum browser support, for..of requires a polyfill for iterators, making your app slightly slower to execute and slightly larger to download.

  • For that reason (and to encourage use of map and filter), some front-end style guides ban for..of completely!

  • But the above concerns is not applicable to Node.js applications, where for..of is now well supported.

  • And furthermore await does not work inside forEach(). Using for..of is the clearest pattern in this case.

Personally, I tend to use whatever looks easiest to read, unless performance or minification has become a major concern. So these days I prefer to use for..of instead of forEach(), but I will always use map or filter or find or some when applicable.
(For the sake of my colleagues, I rarely use reduce.)


How does it work?

for (var i = 0; i < array.length; i++) { ... }   // Forwards

for (var i = array.length; i--; )    { ... }   // Reverse

You will notice that i-- is the middle clause (where we usually see a comparison) and the last clause is empty (where we usually see i++). That means that i-- is also used as the condition for continuation. Crucially, it is executed and checked before each iteration.

  • How can it start at array.length without exploding?

    Because i-- runs before each iteration, on the first iteration we will actually be accessing the item at array.length - 1 which avoids any issues with Array-out-of-bounds undefined items.

  • Why doesn't it stop iterating before index 0?

    The loop will stop iterating when the condition i-- evaluates to a falsey value (when it yields 0).

    The trick is that unlike --i, the trailing i-- operator decrements i but yields the value before the decrement. Your console can demonstrate this:

    > var i = 5; [i, i--, i];

    [5, 5, 4]

    So on the final iteration, i was previously 1 and the i-- expression changes it to 0 but actually yields 1 (truthy), and so the condition passes. On the next iteration i-- changes i to -1 but yields 0 (falsey), causing execution to immediately drop out of the bottom of the loop.

    In the traditional forwards for loop, i++ and ++i are interchangeable (as Douglas Crockford points out). However in the reverse for loop, because our decrement is also our condition expression, we must stick with i-- if we want to process the item at index 0.


Trivia

Some people like to draw a little arrow in the reverse for loop, and end with a wink:

for (var i = array.length; i --> 0 ;) {

Credits go to WYL for showing me the benefits and horrors of the reverse for loop.

‘画卷フ 2025-01-14 03:59:13

一些 C 风格语言使用 foreach 进行循环枚举。在 JavaScript 中,这是通过 for..in< 完成的/code> 循环结构

var index,
    value;
for (index in obj) {
    value = obj[index];
}

有一个问题。 for..in 将循环访问对象的每个可枚举成员及其原型上的成员。为了避免读取通过对象原型继承的值,只需检查该属性是否属于该对象:

for (i in obj) {
    if (obj.hasOwnProperty(i)) {
        //do stuff
    }
}

此外, ECMAScript 5 添加了 forEachArray.prototype 的方法,可用于使用回调枚举数组(polyfill 在文档中,因此您仍然可以在旧版浏览器中使用它):

arr.forEach(function (val, index, theArray) {
    //do stuff
});

需要注意的是,当回调返回 false 时,Array.prototype.forEach 不会中断。 jQueryUnderscore.jseach 上提供了自己的变体,以提供可以短路的循环。

Some C-style languages use foreach to loop through enumerations. In JavaScript this is done with the for..in loop structure:

var index,
    value;
for (index in obj) {
    value = obj[index];
}

There is a catch. for..in will loop through each of the object's enumerable members, and the members on its prototype. To avoid reading values that are inherited through the object's prototype, simply check if the property belongs to the object:

for (i in obj) {
    if (obj.hasOwnProperty(i)) {
        //do stuff
    }
}

Additionally, ECMAScript 5 has added a forEach method to Array.prototype which can be used to enumerate over an array using a calback (the polyfill is in the docs so you can still use it for older browsers):

arr.forEach(function (val, index, theArray) {
    //do stuff
});

It's important to note that Array.prototype.forEach doesn't break when the callback returns false. jQuery and Underscore.js provide their own variations on each to provide loops that can be short-circuited.

自此以后,行同陌路 2025-01-14 03:59:13

为...的|  对于每个|   map

使用现代 JavaScript 语法来迭代数组

const fruits = ['

for...of   |   forEach   |   map

Using modern JavaScript syntax to iterate through arrays

const fruits = ['????', '????', '????' ]

????????   for...of

for (const fruit of fruits) {
    console.log(fruit)  // '????', '????', '????'
}

????????   forEach

fruits.forEach(fruit => {
    console.log(fruit)  // '????', '????', '????'
})

????????   map

*Different from the two above, map() creates a new array and expects you to return something after each iteration.

fruits.map(fruit => fruit)   // ['????', '????', '????' ]

????  Important: As map() is meant to return a value at each iteration, it is an ideal method for transforming elements in arrays:

fruits.map(fruit => 'cool ' + fruit)   // ['cool ????', 'cool ????', 'cool ????' ]

On the other hand, for...of and forEach( ) don't need to return anything and that's why we typically use them to perform logic tasks that manipulate stuff outside.

So to speak, you're going to find if () statements, side effects, and logging activities in these two.

????????  TIP: you can also have the index (as well as the whole array) in each iteration in your .map() or .forEach() functions.

Just pass additional arguments to them:

fruits.map((fruit, i) =>  i + '  ' + fruit)

// ['0 ????', '1 ????', '2 ????' ]

fruits.forEach((f, i, arr) => {
    console.log( f + ' ' + i + ' ' +  arr )
})

// ????  0  ????, ????, ????,
// ????  1  ????, ????, ????,
// ????  2  ????, ????, ????,
嘿看小鸭子会跑 2025-01-14 03:59:13

如果要循环数组,请使用标准的三部分 for 循环。

for (var i = 0; i < myArray.length; i++) {
    var arrayItem = myArray[i];
}

您可以通过缓存 myArray.length 或向后迭代来获得一些性能优化。

If you want to loop over an array, use the standard three-part for loop.

for (var i = 0; i < myArray.length; i++) {
    var arrayItem = myArray[i];
}

You can get some performance optimisations by caching myArray.length or iterating over it backwards.

饭团 2025-01-14 03:59:13

如果您不介意清空数组:

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}

x 将包含 y 的最后一个值,并将其从数组中删除。您还可以使用 shift() 来给出和删除 y 中的第一项。

If you don't mind emptying the array:

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}

x will contain the last value of y and it will be removed from the array. You can also use shift() which will give and remove the first item from y.

滥情哥ㄟ 2025-01-14 03:59:13

forEach 实现(参见 jsFiddle):

function forEach(list,callback) {
  var length = list.length;
  for (var n = 0; n < length; n++) {
    callback.call(list[n]);
  }
}

var myArray = ['hello','world'];

forEach(
  myArray,
  function(){
    alert(this); // do something
  }
);

A forEach implementation (see in jsFiddle):

function forEach(list,callback) {
  var length = list.length;
  for (var n = 0; n < length; n++) {
    callback.call(list[n]);
  }
}

var myArray = ['hello','world'];

forEach(
  myArray,
  function(){
    alert(this); // do something
  }
);
动次打次papapa 2025-01-14 03:59:13

我知道这是一篇旧帖子,并且已经有很多很好的答案。为了更完整一点,我想我应该使用 AngularJS 添加另一个。当然,这仅适用于您使用 Angular 的情况,显然,尽管如此我还是想把它说出来。

angular.forEach 采用 2 个参数和一个可选的第三个参数。第一个参数是要迭代的对象(数组),第二个参数是迭代器函数,可选的第三个参数是对象上下文(在循环内基本上称为“this”)。

使用 forEach 有不同的方法最简单也可能最常用的是

var temp = [1, 2, 3];
angular.forEach(temp, function(item) {
    //item will be each element in the array
    //do something
});

将项目从一个数组复制到另一个数组的另一种方法是

var temp = [1, 2, 3];
var temp2 = [];
angular.forEach(temp, function(item) {
    this.push(item); //"this" refers to the array passed into the optional third parameter so, in this case, temp2.
}, temp2);

,但您不必这样做,您可以简单地执行以下操作,它与前面的示例等效:

angular.forEach(temp, function(item) {
    temp2.push(item);
});

现在各有利弊使用 angular.forEach 函数而不是内置的普通 for 循环

优点

  • 易于阅读
  • 易于书写
  • 如果可用, >angular.forEach 将使用 ES5 forEach 循环。现在,我将在缺点部分讨论效率,因为 forEach 循环比我提到的 for 循环慢得多。专业人士因为保持一致和标准化是件好事,

请考虑以下两个嵌套循环,它们执行完全相同的操作。假设我们有 2 个对象数组,每个对象都包含一个结果数组,每个结果都有一个 Value 属性,该属性是字符串(或其他内容)。假设我们需要迭代每个结果,如果它们相等,则执行一些操作:

angular.forEach(obj1.results, function(result1) {
    angular.forEach(obj2.results, function(result2) {
        if (result1.Value === result2.Value) {
            //do something
        }
    });
});

//exact same with a for loop
for (var i = 0; i < obj1.results.length; i++) {
    for (var j = 0; j < obj2.results.length; j++) {
        if (obj1.results[i].Value === obj2.results[j].Value) {
            //do something
        }
    }
}

当然这是一个非常简单的假设示例,但我已经使用第二种方法编写了三重嵌入 for 循环,并且它是 很难阅读,也很难编写。

缺点

  • 效率。就这一点而言,angular.forEach 和原生 forEach 都比正常 for很多循环......大约慢90%。因此,对于大型数据集,最好坚持使用本机 for 循环。
  • 没有中断、继续或返回支持。 continue 实际上是由“accident”支持的, continue 在 angular.forEach 中,您只需在函数中添加一个 return; 语句,例如 angular.forEach(array, function(item) { if (someConditionIsTrue) return ; }); 这将导致它继续退出该迭代的函数。这也是因为原生 forEach 也不支持 break 或 continue。

我确信还有其他各种优点和缺点,请随意添加您认为合适的任何优点和缺点。我认为,最重要的是,如果您需要效率,请坚持仅使用本机 for 循环来满足您的循环需求。但是,如果您的数据集较小,并且可以放弃一些效率来换取可读性和可写性,那么请务必在那个坏男孩中抛出一个 angular.forEach

I know this is an old post, and there are so many great answers already. For a little more completeness I figured I'd throw in another one using AngularJS. Of course, this only applies if you're using Angular, obviously, nonetheless I'd like to put it anyway.

angular.forEach takes 2 arguments and an optional third argument. The first argument is the object (array) to iterate over, the second argument is the iterator function, and the optional third argument is the object context (basically referred to inside the loop as 'this'.

There are different ways to use the forEach loop of angular. The simplest and probably most used is

var temp = [1, 2, 3];
angular.forEach(temp, function(item) {
    //item will be each element in the array
    //do something
});

Another way that is useful for copying items from one array to another is

var temp = [1, 2, 3];
var temp2 = [];
angular.forEach(temp, function(item) {
    this.push(item); //"this" refers to the array passed into the optional third parameter so, in this case, temp2.
}, temp2);

Though, you don't have to do that, you can simply do the following and it's equivalent to the previous example:

angular.forEach(temp, function(item) {
    temp2.push(item);
});

Now there are pros and cons of using the angular.forEach function as opposed to the built in vanilla-flavored for loop.

Pros

  • Easy readability
  • Easy writability
  • If available, angular.forEach will use the ES5 forEach loop. Now, I will get to efficientcy in the cons section, as the forEach loops are much slower than the for loops. I mention this as a pro because it's nice to be consistent and standardized.

Consider the following 2 nested loops, which do exactly the same thing. Let's say that we have 2 arrays of objects and each object contains an array of results, each of which has a Value property that's a string (or whatever). And let's say we need to iterate over each of the results and if they're equal then perform some action:

angular.forEach(obj1.results, function(result1) {
    angular.forEach(obj2.results, function(result2) {
        if (result1.Value === result2.Value) {
            //do something
        }
    });
});

//exact same with a for loop
for (var i = 0; i < obj1.results.length; i++) {
    for (var j = 0; j < obj2.results.length; j++) {
        if (obj1.results[i].Value === obj2.results[j].Value) {
            //do something
        }
    }
}

Granted this is a very simple hypothetical example, but I've written triple embedded for loops using the second approach and it was very hard to read, and write for that matter.

Cons

  • Efficiency. angular.forEach, and the native forEach, for that matter, are both so much slower than the normal for loop....about 90% slower. So for large data sets, best to stick to the native for loop.
  • No break, continue, or return support. continue is actually supported by "accident", to continue in an angular.forEach you simple put a return; statement in the function like angular.forEach(array, function(item) { if (someConditionIsTrue) return; }); which will cause it to continue out of the function for that iteration. This is also due to the fact that the native forEach does not support break or continue either.

I'm sure there's various other pros and cons as well, and please feel free to add any that you see fit. I feel that, bottom line, if you need efficiency, stick with just the native for loop for your looping needs. But, if your datasets are smaller and a some efficiency is okay to give up in exchange for readability and writability, then by all means throw an angular.forEach in that bad boy.

半城柳色半声笛 2025-01-14 03:59:13

自 ECMAScript 6 起:

list = [0, 1, 2, 3]
for (let obj of list) {
    console.log(obj)
}

其中 of 避免了与 in 相关的奇怪现象,并使其像任何其他语言的 for 循环一样工作,而 let > 在循环内而不是在函数内绑定i

当只有一个命令时(例如上例中),可以省略大括号 ({})。

As of ECMAScript 6:

list = [0, 1, 2, 3]
for (let obj of list) {
    console.log(obj)
}

Where of avoids the oddities associated with in and makes it work like the for loop of any other language, and let binds i within the loop as opposed to within the function.

The braces ({}) can be omitted when there is only one command (e.g. in the example above).

酒儿 2025-01-14 03:59:13

可能 for(i = 0; i < array.length; i++) 循环不是最佳选择。为什么?如果有这样的情况:

var array = new Array();
array[1] = "Hello";
array[7] = "World";
array[11] = "!";

该方法将从 array[0] 调用到 array[2]。首先,这将首先引用您甚至没有的变量,其次,您在数组中不会有这些变量,第三,这将使代码更加大胆。看这里,这就是我使用的:

for(var i in array){
    var el = array[i];
    //If you want 'i' to be INT just put parseInt(i)
    //Do something with el
}

如果你希望它是一个函数,你可以这样做:

function foreach(array, call){
    for(var i in array){
        call(array[i]);
    }
}

如果你想打破,多一点逻辑:

function foreach(array, call){
    for(var i in array){
        if(call(array[i]) == false){
            break;
        }
    }
}

示例:

foreach(array, function(el){
    if(el != "!"){
        console.log(el);
    } else {
        console.log(el+"!!");
    }
});

它返回:

//Hello
//World
//!!!

Probably the for(i = 0; i < array.length; i++) loop is not the best choice. Why? If you have this:

var array = new Array();
array[1] = "Hello";
array[7] = "World";
array[11] = "!";

The method will call from array[0] to array[2]. First, this will first reference variables you don't even have, second you would not have the variables in the array, and third this will make the code bolder. Look here, it's what I use:

for(var i in array){
    var el = array[i];
    //If you want 'i' to be INT just put parseInt(i)
    //Do something with el
}

And if you want it to be a function, you can do this:

function foreach(array, call){
    for(var i in array){
        call(array[i]);
    }
}

If you want to break, a little more logic:

function foreach(array, call){
    for(var i in array){
        if(call(array[i]) == false){
            break;
        }
    }
}

Example:

foreach(array, function(el){
    if(el != "!"){
        console.log(el);
    } else {
        console.log(el+"!!");
    }
});

It returns:

//Hello
//World
//!!!
猫瑾少女 2025-01-14 03:59:13

jQuery 中有 foreach 的三种实现,如下所示。

var a = [3,2];

$(a).each(function(){console.log(this.valueOf())}); //Method 1
$.each(a, function(){console.log(this.valueOf())}); //Method 2
$.each($(a), function(){console.log(this.valueOf())}); //Method 3

There are three implementations of foreach in jQuery as follows.

var a = [3,2];

$(a).each(function(){console.log(this.valueOf())}); //Method 1
$.each(a, function(){console.log(this.valueOf())}); //Method 2
$.each($(a), function(){console.log(this.valueOf())}); //Method 3
停滞 2025-01-14 03:59:13

现在一个简单的解决方案是使用 underscore.js 库。它提供了许多有用的工具,例如 each,并且会自动将作业委托给本机 forEach(如果可用)。

CodePen 示例说明其工作原理:

var arr = ["elemA", "elemB", "elemC"];
_.each(arr, function(elem, index, ar)
{
...
});

另请参阅

  • 本机 Array.prototype.forEach() 的文档。
  • for_each...in< /em> (MDN) 据解释,对于每个(对象中的变量) 作为 ECMA-357 的一部分已被弃用(EAX)标准。
  • for...of (MDN) 描述了使用 for(对象的变量) 作为 Harmony (ECMAScript 6) 提案的一部分进行迭代的下一种方法。

An easy solution now would be to use the underscore.js library. It's providing many useful tools, such as each and will automatically delegate the job to the native forEach if available.

A CodePen example of how it works is:

var arr = ["elemA", "elemB", "elemC"];
_.each(arr, function(elem, index, ar)
{
...
});

See also

花之痕靓丽 2025-01-14 03:59:13

原生 JavaScript 中没有任何 for every 循环。您可以使用库来获取此功能(我推荐 Underscore.js),使用简单的 for in 循环。

for (var instance in objects) {
   ...
}

但是,请注意,可能有理由使用更简单的 for 循环(请参阅 Stack Overflow 问题为什么在数组迭代中使用“for...in”是一个坏主意吗?

var instance;
for (var i=0; i < objects.length; i++) {
    var instance = objects[i];
    ...
}

There isn't any for each loop in native JavaScript. You can either use libraries to get this functionality (I recommend Underscore.js), use a simple for in loop.

for (var instance in objects) {
   ...
}

However, note that there may be reasons to use an even simpler for loop (see Stack Overflow question Why is using “for…in” with array iteration such a bad idea?)

var instance;
for (var i=0; i < objects.length; i++) {
    var instance = objects[i];
    ...
}
ゞ花落谁相伴 2025-01-14 03:59:13

ECMAScript 5(JavaScript 版本)处理数组:

forEach - 迭代数组中的每个项目,并对每个项目执行您需要的操作。

['C', 'D', 'E'].forEach(function(element, index) {
  console.log(element + " is #" + (index+1) + " in the musical scale");
});

// Output
// C is the #1 in musical scale
// D is the #2 in musical scale
// E is the #3 in musical scale

如果您对使用某些内置功能对数组进行操作更感兴趣。

ma​​p - 它使用回调函数的结果创建一个新数组。当您需要格式化数组元素时,可以很好地使用此方法。

// Let's upper case the items in the array
['bob', 'joe', 'jen'].map(function(elem) {
  return elem.toUpperCase();
});

// Output: ['BOB', 'JOE', 'JEN']

reduce - 顾名思义,它通过调用传入当前元素和先前执行结果的给定函数将数组减少为单个值。

[1,2,3,4].reduce(function(previous, current) {
  return previous + current;
});
// Output: 10
// 1st iteration: previous=1, current=2 => result=3
// 2nd iteration: previous=3, current=3 => result=6
// 3rd iteration: previous=6, current=4 => result=10

every - 如果数组中的所有元素都通过回调函数中的测试,则返回 true 或 false。

// Check if everybody has 18 years old of more.
var ages = [30, 43, 18, 5];
ages.every(function(elem) {
  return elem >= 18;
});

// Output: false

filter - 与 every 非常相似,只是过滤器返回一个数组,其中的元素对给定函数返回 true。

// Finding the even numbers
[1,2,3,4,5,6].filter(function(elem){
  return (elem % 2 == 0)
});

// Output: [2,4,6]

ECMAScript 5 (the version on JavaScript) to work with Arrays:

forEach - Iterates through every item in the array and do whatever you need with each item.

['C', 'D', 'E'].forEach(function(element, index) {
  console.log(element + " is #" + (index+1) + " in the musical scale");
});

// Output
// C is the #1 in musical scale
// D is the #2 in musical scale
// E is the #3 in musical scale

In case, more interested on operation on array using some inbuilt feature.

map - It creates a new array with the result of the callback function. This method is good to be used when you need to format the elements of your array.

// Let's upper case the items in the array
['bob', 'joe', 'jen'].map(function(elem) {
  return elem.toUpperCase();
});

// Output: ['BOB', 'JOE', 'JEN']

reduce - As the name says, it reduces the array to a single value by calling the given function passing in the current element and the result of the previous execution.

[1,2,3,4].reduce(function(previous, current) {
  return previous + current;
});
// Output: 10
// 1st iteration: previous=1, current=2 => result=3
// 2nd iteration: previous=3, current=3 => result=6
// 3rd iteration: previous=6, current=4 => result=10

every - Returns true or false if all the elements in the array pass the test in the callback function.

// Check if everybody has 18 years old of more.
var ages = [30, 43, 18, 5];
ages.every(function(elem) {
  return elem >= 18;
});

// Output: false

filter - Very similar to every except that filter returns an array with the elements that return true to the given function.

// Finding the even numbers
[1,2,3,4,5,6].filter(function(elem){
  return (elem % 2 == 0)
});

// Output: [2,4,6]
你好,陌生人 2025-01-14 03:59:13

在 JavaScript 中,有几种方法可以循环遍历数组,如下所示:

for - 这是最常见的方法。用于循环的完整代码块

var languages = ["Java", "JavaScript", "C#", "Python"];
var i, len, text;
for (i = 0, len = languages.length, text = ""; i < len; i++) {
    text += languages[i] + "<br>";
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

while - 当条件满足时循环。这似乎是最快的循环

var text = "";
var i = 0;
while (i < 10) {
    text +=  i + ") something<br>";
    i++;
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

do/while - 在条件为真时也循环执行一段代码,至少运行一次

var text = ""
var i = 0;

do {
    text += i + ") something <br>";
    i++;
}
while (i < 10);

document.getElementById("example").innerHTML = text;
<p id="example"></p>

功能循环 - forEachmapfilter 以及 reduce(它们循环函数,但如果您需要对数组执行某些操作等,则会使用它们。

// For example, in this case we loop through the number and double them up using the map function
var numbers = [65, 44, 12, 4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num * 2});
<p id="example"></p>

有关数组函数式编程的更多信息和示例,请参阅博客文章JavaScript 中的函数式编程:映射、过滤器和归约

There are a few ways to loop through an array in JavaScript, as below:

for - it's the most common one. Full block of code for looping

var languages = ["Java", "JavaScript", "C#", "Python"];
var i, len, text;
for (i = 0, len = languages.length, text = ""; i < len; i++) {
    text += languages[i] + "<br>";
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

while - loop while a condition is through. It seems to be the fastest loop

var text = "";
var i = 0;
while (i < 10) {
    text +=  i + ") something<br>";
    i++;
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

do/while - also loop through a block of code while the condition is true, will run at least one time

var text = ""
var i = 0;

do {
    text += i + ") something <br>";
    i++;
}
while (i < 10);

document.getElementById("example").innerHTML = text;
<p id="example"></p>

Functional loops - forEach, map, filter, also reduce (they loop through the function, but they are used if you need to do something with your array, etc.

// For example, in this case we loop through the number and double them up using the map function
var numbers = [65, 44, 12, 4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num * 2});
<p id="example"></p>

For more information and examples about functional programming on arrays, look at the blog post Functional programming in JavaScript: map, filter and reduce.

空气里的味道 2025-01-14 03:59:13

这是一个非稀疏列表的迭代器,其中索引从 0 开始,这是处理 document.getElementsByTagName 或 document.querySelectorAll 时的典型场景)

function each( fn, data ) {

    if(typeof fn == 'string')
        eval('fn = function(data, i){' + fn + '}');

    for(var i=0, L=this.length; i < L; i++) 
        fn.call( this[i], data, i );   

    return this;
}

Array.prototype.each = each;  

使用示例:

示例 #1< /strong>

var arr = [];
[1, 2, 3].each( function(a){ a.push( this * this}, arr);
arr = [1, 4, 9]

示例 #2

each.call(document.getElementsByTagName('p'), "this.className = data;",'blue');

每个 p 标签都会获得 class="blue"

示例 #3

each.call(document.getElementsByTagName('p'), 
    "if( i % 2 == 0) this.className = data;",
    'red'
);

每个其他 p 标签都会获得class="red">

示例 #4

each.call(document.querySelectorAll('p.blue'), 
    function(newClass, i) {
        if( i < 20 )
            this.className = newClass;
    }, 'green'
);

最后,前 20 个蓝色 p 标签更改为绿色

使用字符串作为函数时的注意事项:该函数是在上下文之外创建的,并且仅应在您确定变量的情况下使用范围界定。否则,最好传递范围更直观的函数。

This is an iterator for NON-sparse list where the index starts at 0, which is the typical scenario when dealing with document.getElementsByTagName or document.querySelectorAll)

function each( fn, data ) {

    if(typeof fn == 'string')
        eval('fn = function(data, i){' + fn + '}');

    for(var i=0, L=this.length; i < L; i++) 
        fn.call( this[i], data, i );   

    return this;
}

Array.prototype.each = each;  

Examples of usage:

Example #1

var arr = [];
[1, 2, 3].each( function(a){ a.push( this * this}, arr);
arr = [1, 4, 9]

Example #2

each.call(document.getElementsByTagName('p'), "this.className = data;",'blue');

Each p tag gets class="blue"

Example #3

each.call(document.getElementsByTagName('p'), 
    "if( i % 2 == 0) this.className = data;",
    'red'
);

Every other p tag gets class="red">

Example #4

each.call(document.querySelectorAll('p.blue'), 
    function(newClass, i) {
        if( i < 20 )
            this.className = newClass;
    }, 'green'
);

And finally the first 20 blue p tags are changed to green

Caution when using string as function: the function is created out-of-context and ought to be used only where you are certain of variable scoping. Otherwise, better to pass functions where scoping is more intuitive.

罪#恶を代价 2025-01-14 03:59:13

尽可能使用 for...of

async/await 支持 跳过非数字属性 不可变索引
为...的

Use for...of where possible

async/await support Skips non-numeric props Immutable index
for...of ???? ???? ????
forEach() ???? ????
for...in ???? ????
Regular for ???? ????

As one can see in the table above, for...of should be used wherever it fits. Since it supports async functions, skips non-numeric properties and prevents messing up the loop by accidentally modifying the loop index.

Syntax

const nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const num of nums) {
  /* Do something with num */
}

See for...of reference for more examples, link to specification and difference between for...of and for...in. Or maybe check this tutorial for some explanation on how they differ.

调妓 2025-01-14 03:59:13

forEach 中没有内置的中断功能。要中断执行,请使用Array#some,如下所示:

[1,2,3].some(function(number) {
    return number === 1;
});

这是有效的,因为只要按数组顺序执行的任何回调返回 true,some 就会返回 true,从而短路其余的执行。
原始答案
请参阅一些的数组原型

There's no inbuilt ability to break in forEach. To interrupt execution use the Array#some like below:

[1,2,3].some(function(number) {
    return number === 1;
});

This works because some returns true as soon as any of the callbacks, executed in array order, returns true, short-circuiting the execution of the rest.
Original Answer
see Array prototype for some

不乱于心 2025-01-14 03:59:13

我还想将其添加为反向循环的组合,并为也喜欢这种语法的人提供上面的答案。

var foo = [object,object,object];
for (var i = foo.length, item; item = foo[--i];) {
    console.log(item);
}

优点:

这样做的好处是:您已经在第一行中获得了引用,以后不需要在另一行中声明。循环对象数组时它很方便。

缺点:

只要引用为 false - falsey(未定义等),这就会中断。但它可以作为一个优势。然而,这会让阅读变得有点困难。而且根据浏览器的不同,它可以“不”优化以比原始浏览器运行得更快。

I also would like to add this as a composition of a reverse loop and an answer above for someone that would like this syntax too.

var foo = [object,object,object];
for (var i = foo.length, item; item = foo[--i];) {
    console.log(item);
}

Pros:

The benefit for this: You have the reference already in the first like that won't need to be declared later with another line. It is handy when looping trough the object array.

Cons:

This will break whenever the reference is false - falsey (undefined, etc.). It can be used as an advantage though. However, it would make it a little bit harder to read. And also depending on the browser it can be "not" optimized to work faster than the original one.

病女 2025-01-14 03:59:13

使用 $.map 的 jQuery 方式:

var data = [1, 2, 3, 4, 5, 6, 7];

var newData = $.map(data, function(element) {
    if (element % 2 == 0) {
        return element;
    }
});

// newData = [2, 4, 6];

jQuery way using $.map:

var data = [1, 2, 3, 4, 5, 6, 7];

var newData = $.map(data, function(element) {
    if (element % 2 == 0) {
        return element;
    }
});

// newData = [2, 4, 6];
旧夏天 2025-01-14 03:59:13

将循环与 ECMAScript 6 解构展开运算符

事实证明,展开运算符的解构和使用对于 ECMAScript 6 的新手来说非常有用,因为它更具人类可读性/美观性,尽管一些 JavaScript 老手可能会认为它凌乱的。青少年或其他一些人可能会发现它很有用。

以下示例将使用 for...of 语句和 .forEach 方法。

示例 6、7 和 8 可与任何函数循环一起使用,例如 .map.filter.reduce .sort.every.some。有关这些方法的更多信息,请查看数组对象 .

示例 1: 普通 for...of 循环 - 这里没有技巧。

let arrSimple = ['a', 'b', 'c'];

for (let letter of arrSimple) {
  console.log(letter);
}

示例 2:将单词拆分为字符

let arrFruits = ['apple', 'orange', 'banana'];

for (let [firstLetter, ...restOfTheWord] of arrFruits) {
  // Create a shallow copy using the spread operator
  let [lastLetter] = [...restOfTheWord].reverse();
  console.log(firstLetter, lastLetter, restOfTheWord);
}

示例 3:使用 keyvalue 进行循环

// let arrSimple = ['a', 'b', 'c'];

// Instead of keeping an index in `i` as per example `for(let i = 0 ; i<arrSimple.length;i++)`
// this example will use a multi-dimensional array of the following format type:
// `arrWithIndex: [number, string][]`

let arrWithIndex = [
  [0, 'a'],
  [1, 'b'],
  [2, 'c'],
];

// Same thing can be achieved using `.map` method
// let arrWithIndex = arrSimple.map((i, idx) => [idx, i]);

// Same thing can be achieved using `Object.entries`
// NOTE: `Object.entries` method doesn't work on Internet Explorer  unless it's polyfilled
// let arrWithIndex = Object.entries(arrSimple);

for (let [key, value] of arrWithIndex) {
  console.log(key, value);
}

示例 4: 内联获取对象属性

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];

for (let { name, age: aliasForAge } of arrWithObjects) {
  console.log(name, aliasForAge);
}

示例 5:获取所需的深层对象属性

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

for (let { name, tags: [firstItemFromTags, ...restOfTags] } of arrWithObjectsWithArr) {
  console.log(name, firstItemFromTags, restOfTags);
}

示例 6:示例 3 是否与 .forEach 一起使用

let arrWithIndex = [
  [0, 'a'],
  [1, 'b'],
  [2, 'c'],
];

// Not to be confused here, `forEachIndex` is the real index
// `mappedIndex` was created by "another user", so you can't really trust it

arrWithIndex.forEach(([mappedIndex, item], forEachIndex) => {
  console.log(forEachIndex, mappedIndex, item);
});

示例 7: 示例 4 是否与 .forEach 一起使用

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];
// NOTE: Destructuring objects while using shorthand functions
// are required to be surrounded by parentheses
arrWithObjects.forEach( ({ name, age: aliasForAge }) => {
  console.log(name, aliasForAge)
});

示例 8: 示例 5 是否与 .forEach 一起使用

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

arrWithObjectsWithArr.forEach(({
  name,
  tags: [firstItemFromTags, ...restOfTags]
}) => {
  console.log(name, firstItemFromTags, restOfTags);
});

Using loops with ECMAScript 6 destructuring and the spread operator

Destructuring and using of the spread operator have proven quite useful for newcomers to ECMAScript 6 as being more human-readable/aesthetic, although some JavaScript veterans might consider it messy. Juniors or some other people might find it useful.

The following examples will use the for...of statement and the .forEach method.

Examples 6, 7, and 8 can be used with any functional loops like .map, .filter, .reduce, .sort, .every, .some. For more information about these methods, check out the Array Object.

Example 1: Normal for...of loop - no tricks here.

let arrSimple = ['a', 'b', 'c'];

for (let letter of arrSimple) {
  console.log(letter);
}

Example 2: Split words to characters

let arrFruits = ['apple', 'orange', 'banana'];

for (let [firstLetter, ...restOfTheWord] of arrFruits) {
  // Create a shallow copy using the spread operator
  let [lastLetter] = [...restOfTheWord].reverse();
  console.log(firstLetter, lastLetter, restOfTheWord);
}

Example 3: Looping with a key and value

// let arrSimple = ['a', 'b', 'c'];

// Instead of keeping an index in `i` as per example `for(let i = 0 ; i<arrSimple.length;i++)`
// this example will use a multi-dimensional array of the following format type:
// `arrWithIndex: [number, string][]`

let arrWithIndex = [
  [0, 'a'],
  [1, 'b'],
  [2, 'c'],
];

// Same thing can be achieved using `.map` method
// let arrWithIndex = arrSimple.map((i, idx) => [idx, i]);

// Same thing can be achieved using `Object.entries`
// NOTE: `Object.entries` method doesn't work on Internet Explorer  unless it's polyfilled
// let arrWithIndex = Object.entries(arrSimple);

for (let [key, value] of arrWithIndex) {
  console.log(key, value);
}

Example 4: Get object properties inline

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];

for (let { name, age: aliasForAge } of arrWithObjects) {
  console.log(name, aliasForAge);
}

Example 5: Get deep object properties of what you need

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

for (let { name, tags: [firstItemFromTags, ...restOfTags] } of arrWithObjectsWithArr) {
  console.log(name, firstItemFromTags, restOfTags);
}

Example 6: Is Example 3 used with .forEach

let arrWithIndex = [
  [0, 'a'],
  [1, 'b'],
  [2, 'c'],
];

// Not to be confused here, `forEachIndex` is the real index
// `mappedIndex` was created by "another user", so you can't really trust it

arrWithIndex.forEach(([mappedIndex, item], forEachIndex) => {
  console.log(forEachIndex, mappedIndex, item);
});

Example 7: Is Example 4 used with .forEach

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];
// NOTE: Destructuring objects while using shorthand functions
// are required to be surrounded by parentheses
arrWithObjects.forEach( ({ name, age: aliasForAge }) => {
  console.log(name, aliasForAge)
});

Example 8: Is Example 5 used with .forEach

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

arrWithObjectsWithArr.forEach(({
  name,
  tags: [firstItemFromTags, ...restOfTags]
}) => {
  console.log(name, firstItemFromTags, restOfTags);
});

梦萦几度 2025-01-14 03:59:13

摘要:

在迭代数组时,我们通常希望实现以下目标之一:

  1. 我们希望迭代数组并创建一个新数组:

    Array.prototype.map

  2. 我们想要迭代数组并且不创建新数组:

    Array.prototype.forEach

    for..of loop

在 JavaScript 中,有很多方法可以实现这两个目标。然而,有些比其他更方便。下面你可以找到一些常用的方法(我认为是最方便的)在 JavaScript 中完成数组迭代。

创建新数组: Map

map() 是位于 Array.prototype 上的函数,它可以转换数组的每个元素,然后返回一个 <强>新数组。 map() 将回调函数作为参数,并按以下方式工作:

let arr = [1, 2, 3, 4, 5];

let newArr = arr.map((element, index, array) => {
  return element * 2;
})

console.log(arr);
console.log(newArr);

我们作为参数传递给 map() 的回调将针对每个元素执行。然后返回一个与原始数组长度相同的数组。在此新数组元素中,通过作为参数传递给 map() 的回调函数进行转换。

map 与另一种循环机制(例如 forEachfor..of 循环)之间的明显区别在于 map 返回一个新数组并保持旧数组完好无损(除非您使用类似于 splice 的方式显式操作它)。

另请注意,map 函数的回调提供当前迭代的索引号作为第二个参数。此外,第三个参数是否提供了调用 map 的数组?有时这些属性非常有用。

使用 forEach 进行循环

forEach 是一个位于 Array.prototype 上的函数,它接受回调函数作为参数。然后它对数组中的每个元素执行此回调函数。与 map() 函数相反,forEach 函数不返回任何内容 (undefined)。例如:

let arr = [1, 2, 3, 4, 5];

arr.forEach((element, index, array) => {

  console.log(element * 2);

  if (index === 4) {
    console.log(array)
  }
  // index, and oldArray are provided as 2nd and 3th argument by the callback

})

console.log(arr);

就像 map 函数一样,forEach 回调提供当前迭代的索引号作为第二个参数。另外,第三个参数是否提供了调用 forEach 的数组?

使用 for..of 循环遍历元素

for..of 循环循环遍历数组(或任何其他可迭代对象)的每个元素。它按以下方式工作:

let arr = [1, 2, 3, 4, 5];

for(let element of arr) {
  console.log(element * 2);
}

在上面的例子中,element代表数组元素,arr是我们要循环的数组。请注意,名称 element 是任意的,我们可以选择任何其他名称,例如“el”或在适用时更具声明性的名称。

不要将 for..in 循环与 for..of 循环混淆。 for..in 将循环遍历数组的所有可枚举属性,而 for..of 循环将仅循环遍历数组元素。例如:

let arr = [1, 2, 3, 4, 5];

arr.foo = 'foo';

for(let element of arr) {
  console.log(element);
}

for(let element in arr) {
  console.log(element);
}

Summary:

When iterating over an array, we often want to accomplish one of the following goals:

  1. We want to iterate over the array and create a new array:

    Array.prototype.map

  2. We want to iterate over the array and don't create a new array:

    Array.prototype.forEach

    for..of loop

In JavaScript, there are many ways of accomplishing both of these goals. However, some are more convenient than others. Below you can find some commonly used methods (the most convenient IMO) to accomplish array iteration in JavaScript.

Creating new array: Map

map() is a function located on Array.prototype which can transform every element of an array and then returns a new array. map() takes as an argument a callback function and works in the following manner:

let arr = [1, 2, 3, 4, 5];

let newArr = arr.map((element, index, array) => {
  return element * 2;
})

console.log(arr);
console.log(newArr);

The callback which we have passed into map() as an argument gets executed for every element. Then an array gets returned which has the same length as the original array. In this new array element is transformed by the callback function passed in as an argument to map().

The distinct difference between map and another loop mechanism like forEach and a for..of loop is that map returns a new array and leaves the old array intact (except if you explicitly manipulate it with thinks like splice).

Also, note that the map function's callback provides the index number of the current iteration as a second argument. Furthermore, does the third argument provide the array on which map was called? Sometimes these properties can be very useful.

Loop using forEach

forEach is a function which is located on Array.prototype which takes a callback function as an argument. It then executes this callback function for every element in the array. In contrast to the map() function, the forEach function returns nothing (undefined). For example:

let arr = [1, 2, 3, 4, 5];

arr.forEach((element, index, array) => {

  console.log(element * 2);

  if (index === 4) {
    console.log(array)
  }
  // index, and oldArray are provided as 2nd and 3th argument by the callback

})

console.log(arr);

Just like the map function, the forEach callback provides the index number of the current iteration as a second argument. Also, does the third argument provide the array on which forEach was called?

Loop through elements using for..of

The for..of loop loops through every element of an array (or any other iterable object). It works in the following manner:

let arr = [1, 2, 3, 4, 5];

for(let element of arr) {
  console.log(element * 2);
}

In the above example, element stands for an array element and arr is the array which we want to loop. Note that the name element is arbitrary, and we could have picked any other name like 'el' or something more declarative when this is applicable.

Don't confuse the for..in loop with the for..of loop. for..in will loop through all enumerable properties of the array whereas the for..of loop will only loop through the array elements. For example:

let arr = [1, 2, 3, 4, 5];

arr.foo = 'foo';

for(let element of arr) {
  console.log(element);
}

for(let element in arr) {
  console.log(element);
}

独自←快乐 2025-01-14 03:59:13

今天

(2019-12-18)我在我的 macOS v10.13.6 (High Sierra ),在 Chrome v 79.0、Safari v13.0.4 和 Firefox v71.0(64 位)上 - 关于优化的结论(以及 微优化通常不值得介绍它来编码,因为好处很小,但代码复杂性会增加)。

  • 看起来传统的 for i (Aa) 是在所有浏览器上编写快速代码的不错选择。

  • 其他解决方案,例如 for-of (Ad),都在 C 组中。...通常为 2 - 10 (以及更多)比 Aa 慢很多倍,但是对于小型数组,可以使用它 - 为了提高代码清晰度。

  • 缓存在nAb、Bb、Be)中的数组长度的循环有时更快,有时则不然。编译器可能会自动检测这种情况并引入缓存。缓存版本和无缓存版本(Aa、Ba、Bd)之间的速度差异约为 1%,因此看起来引入 n 是一个<一个href="https://stackoverflow.com/questions/3470990/is-micro-optimization-worth-the-time/3471000#3471000">微优化

  • 类似 i-- 的解决方案,其中循环从最后一个数组元素(Ac, Bc)开始,通常比正向解决方案慢约 30% - 可能是原因是CPU内存缓存工作的方式 - 正向内存读取更优化用于 CPU 缓存)。 建议不要使用此类解决方案。

详细信息

在测试中,我们计算数组元素的总和。我对小数组(10 个元素)和大数组(1M 元素)进行测试,并将它们分为三组:

  • A - for 测试
  • B - while 测试
  • C - 其他/替代方法
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
//let arr = Array.from(Array(1000000), (x, i) => i%10);

function Aa(a, s=0) {
  for(let i=0; i<a.length; i++) {
    s += a[i];
  }
  console.log('Aa=', s);
}

function Ab(a, s=0) {
  let n = a.length;
  for(let i=0; i<n; i++) {
    s += a[i];
  }
  console.log('Ab=', s);
}

function Ac(a, s=0) {
  for(let i=a.length; i--;) {
    s += a[i];
  }
  console.log('Ac=', s);
}

function Ad(a, s=0) {
  for(let x of a) {
    s += x;
  }
  console.log('Ad=', s);
}

function Ae(a, s=0) {
  for(let i in a) if (a.hasOwnProperty(i)) {
    s += a[i];
  }
  console.log('Ae=', s);
}

function Ba(a, s=0) {
  let i = -1;
  while(++i < a.length) {
    s+= a[i];
  }
  console.log('Ba=', s);
}

function Bb(a, s=0) {
  let i = -1;
  let n = a.length;
  while(++i < n) {
    s+= a[i];
  }
  console.log('Bb=', s);
}

function Bc(a, s=0) {
  let i = a.length;
  while(i--) {
    s += a[i];
  }
  console.log('Bc=', s);
}

function Bd(a, s=0) {
  let i = 0;
  do {
    s+= a[i]
  } while (++i < a.length);
  console.log('Bd=', s);
}

function Be(a, s=0) {
  let i = 0;
  let n = a.length;
  do {
    s += a[i]
  } while (++i < n);
  console.log('Be=', s);
}

function Bf(a, s=0) {
  const it = a.values(); 
  let e;
  while (!(e = it.next()).done) { 
    s+= e.value; 
  }
  console.log('Bf=', s);
}

function Ca(a, s=0) {
  a.map(x => { s+=x });
  console.log('Ca=', s);
}

function Cb(a, s=0) {
  a.forEach(x => { s+=x });
  console.log('Cb=', s);
}

function Cc(a, s=0) {
  a.every(x => (s += x, 1));
  console.log('Cc=', s);
}

function Cd(a, s=0) {
  a.filter(x => { s+=x });
  console.log('Cd=',s);
}

function Ce(a, s=0) {
  a.reduce((z, c) => { s+=c }, 0);
  console.log('Ce=', s);
}

function Cf(a, s=0) {
  a.reduceRight((z, c) => { s += c }, 0);
  console.log('Cf=', s);
}

function Cg(a, s=0) {
  a.some(x => { s += x } );
  console.log('Cg=', s);
}

function Ch(a, s=0) {
  Array.from(a, x=> s += x);
  console.log('Cc=', s);
}


Aa(arr);
Ab(arr);
Ac(arr);
Ad(arr);
Ae(arr);

Ba(arr);
Bb(arr);
Bc(arr);
Bd(arr);
Be(arr);
Bf(arr);

Ca(arr);
Cb(arr);
Cc(arr);
Cd(arr);
Ce(arr);
Cf(arr);
Cg(arr);
Ch(arr);
<p style="color: red">This snippets only PRESENTS code used for benchmark - it not perform test itself</p>

跨浏览器结果

所有测试浏览器的结果

在此处输入图像描述浏览器**

包含 10 个元素的数组

Chrome 的结果。您可以在此处在您的计算机上执行测试。

输入图像描述此处

包含 1,000,000 个元素的数组

Chrome 的结果。 在您的计算机上执行测试

您可以在此处 在此处输入图像描述

Performance

Today (2019-12-18) I perform test on my macOS v10.13.6 (High Sierra), on Chrome v 79.0, Safari v13.0.4 and Firefox v71.0 (64 bit) - conclusions about optimisation (and micro-optimisation which usually is not worth to introduce it to code because the benefit is small, but code complexity grows).

  • It looks like the traditional for i (Aa) is a good choice to write fast code on all browsers.

  • The other solutions, like for-of (Ad), all in group C.... are usually 2 - 10 (and more) times slower than Aa, but for small arrays it is ok to use it - for the sake of increase code clarity.

  • The loops with array length cached in n (Ab, Bb, Be) are sometimes faster, sometimes not. Probably compilers automatically detect this situation and introduce caching. The speed differences between the cached and no-cached versions (Aa, Ba, Bd) are about ~1%, so it looks like introduce n is a micro-optimisation.

  • The i-- like solutions where the loop starts from the last array element (Ac, Bc) are usually ~30% slower than forward solutions - probably the reason is the way of CPU memory cache working - forward memory reading is more optimal for CPU caching). Is recommended to NOT USE such solutions.

Details

In tests we calculate the sum of array elements. I perform a test for small arrays (10 elements) and big arrays (1M elements) and divide them into three groups:

  • A - for tests
  • B - while tests
  • C - other/alternative methods

let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
//let arr = Array.from(Array(1000000), (x, i) => i%10);

function Aa(a, s=0) {
  for(let i=0; i<a.length; i++) {
    s += a[i];
  }
  console.log('Aa=', s);
}

function Ab(a, s=0) {
  let n = a.length;
  for(let i=0; i<n; i++) {
    s += a[i];
  }
  console.log('Ab=', s);
}

function Ac(a, s=0) {
  for(let i=a.length; i--;) {
    s += a[i];
  }
  console.log('Ac=', s);
}

function Ad(a, s=0) {
  for(let x of a) {
    s += x;
  }
  console.log('Ad=', s);
}

function Ae(a, s=0) {
  for(let i in a) if (a.hasOwnProperty(i)) {
    s += a[i];
  }
  console.log('Ae=', s);
}

function Ba(a, s=0) {
  let i = -1;
  while(++i < a.length) {
    s+= a[i];
  }
  console.log('Ba=', s);
}

function Bb(a, s=0) {
  let i = -1;
  let n = a.length;
  while(++i < n) {
    s+= a[i];
  }
  console.log('Bb=', s);
}

function Bc(a, s=0) {
  let i = a.length;
  while(i--) {
    s += a[i];
  }
  console.log('Bc=', s);
}

function Bd(a, s=0) {
  let i = 0;
  do {
    s+= a[i]
  } while (++i < a.length);
  console.log('Bd=', s);
}

function Be(a, s=0) {
  let i = 0;
  let n = a.length;
  do {
    s += a[i]
  } while (++i < n);
  console.log('Be=', s);
}

function Bf(a, s=0) {
  const it = a.values(); 
  let e;
  while (!(e = it.next()).done) { 
    s+= e.value; 
  }
  console.log('Bf=', s);
}

function Ca(a, s=0) {
  a.map(x => { s+=x });
  console.log('Ca=', s);
}

function Cb(a, s=0) {
  a.forEach(x => { s+=x });
  console.log('Cb=', s);
}

function Cc(a, s=0) {
  a.every(x => (s += x, 1));
  console.log('Cc=', s);
}

function Cd(a, s=0) {
  a.filter(x => { s+=x });
  console.log('Cd=',s);
}

function Ce(a, s=0) {
  a.reduce((z, c) => { s+=c }, 0);
  console.log('Ce=', s);
}

function Cf(a, s=0) {
  a.reduceRight((z, c) => { s += c }, 0);
  console.log('Cf=', s);
}

function Cg(a, s=0) {
  a.some(x => { s += x } );
  console.log('Cg=', s);
}

function Ch(a, s=0) {
  Array.from(a, x=> s += x);
  console.log('Cc=', s);
}


Aa(arr);
Ab(arr);
Ac(arr);
Ad(arr);
Ae(arr);

Ba(arr);
Bb(arr);
Bc(arr);
Bd(arr);
Be(arr);
Bf(arr);

Ca(arr);
Cb(arr);
Cc(arr);
Cd(arr);
Ce(arr);
Cf(arr);
Cg(arr);
Ch(arr);
<p style="color: red">This snippets only PRESENTS code used for benchmark - it not perform test itself</p>

Cross browser results

Results for all tested browsers

Enter image description herebrowsers**

Array with 10 elements

Results for Chrome. You can perform the test on your machine here.

Enter image description here

Array with 1,000,000 elements

Results for Chrome. You can perform the test on your machine here

Enter image description here

月亮邮递员 2025-01-14 03:59:13

最接近您想法的方法是使用 Array.forEach() ,它接受一个将为数组的每个元素执行的闭包函数。

myArray.forEach(
  (item) => {
    // Do something
    console.log(item);
  }
);

另一种可行的方法是使用 Array.map() ,它的工作方式相同,但它也会获取您返回的所有值并将它们返回到一个新数组中(本质上将每个元素映射到一个新的数组)一),像这样:

var myArray = [1, 2, 3];
myArray = myArray.map(
  (item) => {
    return item + 1;
  }
);

console.log(myArray); // [2, 3, 4]

A way closest to your idea would be to use Array.forEach() which accepts a closure function which will be executed for each element of the array.

myArray.forEach(
  (item) => {
    // Do something
    console.log(item);
  }
);

Another viable way would be to use Array.map() which works in the same way, but it also takes all values that you return and returns them in a new array (essentially mapping each element to a new one), like this:

var myArray = [1, 2, 3];
myArray = myArray.map(
  (item) => {
    return item + 1;
  }
);

console.log(myArray); // [2, 3, 4]
横笛休吹塞上声 2025-01-14 03:59:13

根据新的更新功能 ECMAScript 6 (ES6) 和 ECMAScript 2015,您可以将以下选项与循环一起使用:

for循环

for(var i = 0; i < 5; i++){
  console.log(i);
}

// Output: 0,1,2,3,4

for...in 循环

let obj = {"a":1, "b":2}

for(let k in obj){
  console.log(k)
}

// Output: a,b

Array.forEach()

let array = [1,2,3,4]

array.forEach((x) => {
  console.log(x);
})

// Output: 1,2,3,4

for...of 循环

let array = [1,2,3,4]

for(let x of array){
  console.log(x);
}

// Output: 1,2,3,4

while 循环

let x = 0

while(x < 5){
  console.log(x)
  x++
}

// Output: 1,2,3,4

do...while 循环

let x = 0

do{
  console.log(x)
  x++
}while(x < 5)

// Output: 1,2,3,4

As per the new updated feature ECMAScript 6 (ES6) and ECMAScript 2015, you can use the following options with loops:

for loops

for(var i = 0; i < 5; i++){
  console.log(i);
}

// Output: 0,1,2,3,4

for...in loops

let obj = {"a":1, "b":2}

for(let k in obj){
  console.log(k)
}

// Output: a,b

Array.forEach()

let array = [1,2,3,4]

array.forEach((x) => {
  console.log(x);
})

// Output: 1,2,3,4

for...of loops

let array = [1,2,3,4]

for(let x of array){
  console.log(x);
}

// Output: 1,2,3,4

while loops

let x = 0

while(x < 5){
  console.log(x)
  x++
}

// Output: 1,2,3,4

do...while loops

let x = 0

do{
  console.log(x)
  x++
}while(x < 5)

// Output: 1,2,3,4
叫思念不要吵 2025-01-14 03:59:13

lambda 语法通常不适用于 Internet Explorer 10 或更低版本。

我通常使用

[].forEach.call(arrayName,function(value,index){
    console.log("value of the looped element" + value);
    console.log("index of the looped element" + index);
});

如果您是 jQuery 粉丝并且已经运行了 jQuery 文件,则应该反转索引和值参数的位置

$("#ul>li").each(function(**index, value**){
    console.log("value of the looped element" + value);
    console.log("index of the looped element" + index);
});

The lambda syntax doesn't usually work in Internet Explorer 10 or below.

I usually use the

[].forEach.call(arrayName,function(value,index){
    console.log("value of the looped element" + value);
    console.log("index of the looped element" + index);
});

If you are a jQuery fan and already have a jQuery file running, you should reverse the positions of the index and value parameters

$("#ul>li").each(function(**index, value**){
    console.log("value of the looped element" + value);
    console.log("index of the looped element" + index);
});
傲娇萝莉攻 2025-01-14 03:59:13

您可以像这样调用 forEach:

forEach 将迭代您提供的数组,并且对于每次迭代,它将有 element 保存该迭代的值。如果您需要索引,您可以通过将 i 作为 forEach 回调函数中的第二个参数传递来获取当前索引。

Foreach 基本上是一个高阶函数,它接受另一个函数作为其参数。

let theArray= [1,3,2];

theArray.forEach((element) => {
  // Use the element of the array
  console.log(element)
}

输出:

1
3
2

您还可以像这样迭代数组:

for (let i=0; i<theArray.length; i++) {
  console.log(i); // i will have the value of each index
}

You can call forEach like this:

forEach will iterate over the array you provide and for each iteration it will have element which holds the value of that iteration. If you need index you can get the current index by passing the i as the second parameter in the callback function for forEach.

Foreach is basically a High Order Function, Which takes another function as its parameter.

let theArray= [1,3,2];

theArray.forEach((element) => {
  // Use the element of the array
  console.log(element)
}

Output:

1
3
2

You can also iterate over an array like this:

for (let i=0; i<theArray.length; i++) {
  console.log(i); // i will have the value of each index
}
尘曦 2025-01-14 03:59:13

如果你想使用 forEach(),它会看起来像 -

theArray.forEach ( element => {
    console.log(element);
});

如果你想使用 for(),它会看起来像 -

for(let idx = 0; idx < theArray.length; idx++){
    let element = theArray[idx];
    console.log(element);
}

If you want to use forEach(), it will look like -

theArray.forEach ( element => {
    console.log(element);
});

If you want to use for(), it will look like -

for(let idx = 0; idx < theArray.length; idx++){
    let element = theArray[idx];
    console.log(element);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文