在 JavaScript 中循环(foreach)数组
如何使用 JavaScript 循环遍历数组中的所有条目?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
如何使用 JavaScript 循环遍历数组中的所有条目?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(30)
TL;DR
您最好的选择通常是
for-of
循环(仅限 ES2015+;规范 | MDN< /a>) - 简单且异步友好forEach
(仅限 ES5+;规范 | MDN)(或其亲属)some
等) - 不异步
友好(但请参阅详细信息)for
循环 -async
- 友好for-in
有保护措施 -异步
友好一些快速的“不要”:
for-in
,除非您在使用时有防护措施,或者至少知道它为什么会咬您。map
的返回值,就不要使用它。(遗憾的是有人在教
map< /code> [规范 / MDN] 就好像它是
forEach
—但正如我在博客上写的那样,这不是它的用途。如果您不使用它创建的数组,请不要使用map
。)forEach
等待该工作完成(因为它不会)。但是还有很多更多内容需要探索,请继续阅读...
JavaScript 具有强大的语义来循环遍历数组和类似数组的对象。我将答案分为两部分:真正数组的选项,以及类似于数组的选项,例如参数对象、其他可迭代对象( ES2015+)、DOM 集合等等。
好的,让我们看看我们的选项:
对于实际数组,
您有五个选项(两个基本上永远支持,另一个由 ECMAScript 5 [“ES5”] 添加,另外两个在 ECMAScript 2015 中添加(“ES2015”,又名“ES6”) ):
for-of
(隐式使用迭代器) (ES2015+)forEach
及相关(ES5+)for
循环for-in
正确(您可以在此处查看那些旧规范: ES5,ES2015,但两者均已被取代;当前编辑的草稿始终是 此处。)
详细信息:
1. 使用
for-of
(隐式使用迭代器) (ES2015+)ES2015 添加了迭代器和可迭代对象到 JavaScript。数组是可迭代的(字符串、Map 和 Set 以及 DOM 集合和列表也是如此,稍后您将看到)。可迭代对象为其值提供迭代器。新的
for-of
语句循环遍历迭代器返回的值:没有比这更简单的了!在幕后,它从数组中获取迭代器并循环遍历迭代器返回的值。数组提供的迭代器按从开始到结束的顺序提供数组元素的值。
请注意
element
如何将范围限定为每个循环迭代;尝试在循环结束后使用element
将会失败,因为它不存在于循环体之外。理论上,
for-of
循环涉及多个函数调用(一个用于获取迭代器,然后一个用于从中获取每个值)。即使这是真的,也无需担心,在现代 JavaScript 引擎中,函数调用非常很便宜(它让我为forEach
[如下]感到困扰直到我研究它;详细信息)。但此外,在处理数组等内容的本机迭代器时,JavaScript 引擎会优化这些调用(在性能关键的代码中)。for-of
完全是异步
友好的。如果您需要串行(而不是并行)完成循环体中的工作,则循环体中的await
将等待 Promise 解决后再继续。这是一个愚蠢的例子:请注意单词在每个单词之前出现的时间是如何延迟的。
这是编码风格的问题,但是
for-of
是我在循环任何可迭代对象时首先要做的事情。2. 使用
forEach
及相关内容在任何可以访问 ES5 添加的
Array
功能的现代环境(因此,不是 IE8)中,您都可以使用forEach
(规范 |forEach
接受一个回调函数,并且可以选择在调用该回调时用作this
的值(上面未使用)。按顺序为数组中的每个元素调用回调,跳过稀疏数组中不存在的元素。虽然上面我只使用了一个参数,但回调函数是通过三个参数调用的:该迭代的元素、该元素的索引以及对要迭代的数组的引用(如果您的函数还没有它)便利)。与
for-of
一样,forEach
的优点是您不必在包含范围内声明索引和值变量;在这种情况下,它们作为迭代函数的参数提供,因此很好地限定了该迭代。与
for-of
不同,forEach
的缺点是它不理解async
函数和await
。如果您使用async
函数作为回调,forEach
不会等待该函数的 Promise 解决后再继续。这是来自for-of
的async
示例,使用forEach
代替 - 请注意初始延迟,但随后所有文本立即显示等待时间: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
函数回调永远不适合every
、some
和filter
因为它们会处理返回的承诺就好像它是一个真实值一样;他们不会等待承诺解决然后使用履行价值。async
函数回调通常适合map
,如果目标是将某项数组转换为 Promise 数组,也许用于传递给 Promise 组合器函数之一(Promise.all
,Promise.race
,promise.allSettled
,或 < a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise/any" rel="noreferrer">Promise.any
)。async
函数回调很少适合于reduce
或reduceRight
,因为(再次)回调将始终返回一个 Promise。但是有一种习惯用法是使用reduce
(const Promise = array.reduce((p, element) => p.then(/*. ..使用 `element`...*/));
) 的东西,但通常在这些情况下for-of
或for
循环位于 < code>async 函数会更清晰,更容易调试。3. 使用简单的
for
循环有时旧的方法是最好的:
如果数组的长度在循环期间不会改变,并且它是在对性能高度敏感的代码中,则预先获取长度的稍微复杂的版本可能是一个微小 快一点:
和/或倒数:
但对于现代 JavaScript 引擎,您很少需要竭尽全力。
在 ES2015 之前,循环变量必须存在于包含作用域中,因为 var 仅具有函数级作用域,而没有块级作用域。但正如您在上面的示例中看到的,您可以在
for
中使用let
将变量的范围限定为循环。当您这样做时,会为每个循环迭代重新创建index
变量,这意味着在循环体中创建的闭包会保留对该特定迭代的index
的引用,这解决了老的“循环闭包”问题:在上面,如果单击第一个,您将得到“Index is: 0”,如果单击最后一个,您将得到“Index is: 4”。如果您使用
var
而不是let
,这不起作用(您总是会看到“Index is: 5”)。与
for-of
一样,for
循环在async
函数中运行良好。下面是之前使用for
循环的示例:4. 正确使用
for-in
for-in
不是用于循环数组,而是用于循环对象的属性名称。作为数组是对象这一事实的副产品,它似乎经常适用于循环数组,但它不仅仅循环遍历数组索引,它还循环遍历数组的所有可枚举属性。对象(包括继承的对象)。 (过去也没有指定顺序;现在是[这个其他答案中的详细信息],但是即使现在指定了顺序,但规则很复杂,也有例外,并且依赖顺序并不是最佳实践。)数组上
for-in
的唯一实际用例是仅查看第一个示例:如果您使用适当的保障措施:
请注意这三项检查:
该对象是否拥有该名称的自己属性(不是从其原型继承的属性;此检查通常也写为
a.hasOwnProperty(name)
但 ES2022 添加了Object.hasOwn
更可靠),以及名称全部是十进制数字(例如,正常字符串形式,而不是科学记数法),并且
强制转换为数字时名称的值为 <= 2^32 - 2(即 4,294,967,294)。这个数字从哪里来?它是规范中数组索引定义的一部分。其他数字(非整数、负数、大于 2^32 - 2 的数字)不是数组索引。之所以是 2^32 - 2 是因为这使得最大索引值比 2^32 - 1 小 1,后者是数组
长度的最大值
可以有。 (例如,数组的长度适合 32 位无符号整数。)...尽管如此,大多数代码仅执行
hasOwnProperty
检查。当然,在内联代码中您不会这样做。您将编写一个实用函数。也许:
与
for
类似,如果其中的工作需要串行完成,for-in
在异步函数中效果很好。5. 显式使用迭代器 (ES2015+)
for-of
隐式使用迭代器,为您完成所有 scut 工作。有时,您可能想要显式使用迭代器。它看起来像这样:迭代器是与规范中的迭代器定义相匹配的对象。每次调用它的
next
方法时都会返回一个新的结果对象。结果对象有一个属性done
,告诉我们它是否完成,还有一个属性value
,其中包含该迭代的值。 如果done
为false
,则done
是可选的;如果value
为undefined
,则为可选。)( get for
value
因迭代器而异。对于数组,默认迭代器提供每个数组元素的值(示例中的"a"
、"b"
和"c"
较早)。数组还有其他三个返回迭代器的方法:values()
:这是返回默认迭代器的[Symbol.iterator]
方法的别名。keys()
:返回提供数组中每个键(索引)的迭代器。在上面的示例中,它将提供0
,然后是1
,然后是2
(作为数字,而不是字符串)。 (另请注意,在稀疏数组中,它 将包含不存在的元素的索引。)entries()
:返回一个提供[key, value]
数组。由于迭代器对象在调用
next
之前不会前进,因此它们在async
函数循环中运行良好。下面是之前显式使用迭代器的for-of
示例:对于类似数组的对象
除了真正的数组之外,还有一些类似数组的对象,它们具有
length
属性和具有全数字名称的属性:NodeList
实例,HTMLCollection
实例、arguments
对象等。我们如何循环访问它们的内容?使用上面的大多数选项
上面的数组方法中至少有一些,可能是大多数甚至全部都同样适用于类似数组的对象:
使用
for-of
(使用隐式迭代器)(ES2015+)for-of
使用迭代器 由对象提供(如果有)。这包括主机提供的对象(例如 DOM 集合和列表)。例如,来自getElementsByXYZ
方法的HTMLCollection
实例和来自querySelectorAll
的NodeList
实例都支持迭代。 (这是由 HTML 和 DOM 规范相当巧妙地定义的。基本上,任何具有长度
和索引访问的对象都是自动可迭代的。它不 > 必须标记为iterable
;仅用于除了可迭代之外还支持forEach
、values
、的集合键
,entries
方法没有;HTMLCollection
没有,但两者都是可迭代的。)下面是循环
div
元素的示例:使用
forEach
及相关 (ES5+)Array.prototype 上的各种函数都是“有意通用的”,可以通过
Function#call
(规范 | MDN) 或Function#apply
(规范 | MDN)。 (如果您必须处理 IE8 或更早版本 [哎哟],请参阅本答案末尾的“主机提供的对象的警告”,但这对于模糊现代的浏览器来说不是问题。)假设您想在
Node
的childNodes
集合(它是一个HTMLCollection
)上使用forEach
,本身没有forEach
)。你会这样做:(但请注意,您可以在
node.childNodes
上使用for-of
。)如果您要经常这样做,您可能需要将函数引用的副本获取到变量中以供重用,例如:
使用简单的
for
循环也许显然,一个简单的
for
循环适用于类似数组的对象。显式使用迭代器 (ES2015+)
参见#1。
您也许可以通过
for-in
(有保障措施)逃脱惩罚,但是有了所有这些更合适的选项,没有理由尝试。创建真正的数组
有时,您可能希望将类似数组的对象转换为真正的数组。做到这一点非常简单:
使用
Array.from
Array.from
(规范) | (MDN)(ES2015+,但很容易填充)创建来自类数组对象的数组,可以选择首先通过映射函数传递条目。所以:...从
querySelectorAll
获取NodeList
并从中创建一个数组。如果您要以某种方式映射内容,映射功能会很方便。例如,如果您想获取具有给定类的元素的标签名称数组:
使用扩展语法 (
...
)也可以使用 ES2015 的扩展语法。与
for-of
一样,它使用 迭代器 由对象提供(请参阅上一节中的 #1):例如,如果我们想将
NodeList
转换为真正的数组,使用扩展语法,这会变得非常简洁:<强>使用数组的
slice
方法我们可以使用
slice
方法数组,与上面提到的其他方法一样,它是“有意通用的”,因此可以与类似数组的对象一起使用,如下所示:例如,如果我们想将
NodeList
转换为真正的数组,我们可以这样做:(如果您仍然需要处理 IE8 [哎哟],将会失败;IE8 不允许您像这样使用主机提供的对象作为
this
。)> this 喜欢
如果使用
array.protype
使用主机提供的 array类似阵列的对象(例如,dom dom)收藏品以及此类浏览器而不是JavaScript引擎),像IE8这样的过时的浏览器不一定会处理这种方式,因此,如果您必须支持它们,请确保在目标环境中测试。但这不是现代浏览器的问题。 (对于非浏览器环境,自然会取决于环境。)TL;DR
Your best bets are usually
for-of
loop (ES2015+ only; spec | MDN) - simple andasync
-friendlyforEach
(ES5+ only; spec | MDN) (or its relativessome
and such) - notasync
-friendly (but see details)for
loop -async
-friendlyfor-in
with safeguards -async
-friendlySome quick "don't"s:
for-in
unless you use it with safeguards or are at least aware of why it might bite you.map
if you're not using its return value.(There's sadly someone out there teaching
map
[spec / MDN] as though it wereforEach
— 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 usemap
.)forEach
if the callback does asynchronous work and you want theforEach
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"):
for-of
(use an iterator implicitly) (ES2015+)forEach
and related (ES5+)for
loopfor-in
correctly(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,
Map
s, andSet
s, as well as DOM collections and lists, as you'll see later). Iterable objects provide iterators for their values. The newfor-of
statement loops through the values returned by an iterator: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 useelement
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 forforEach
[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 entirelyasync
-friendly. If you need the work in a loop body to be done in series (not in parallel), anawait
in the loop body will wait for the promise to settle before continuing. Here's a silly example: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 relatedIn any even vaguely-modern environment (so, not IE8) where you have access to the
Array
features added by ES5, you can useforEach
(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):forEach
accepts a callback function and, optionally, a value to use asthis
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 understandasync
functions andawait
. If you use anasync
function as the callback,forEach
does not wait for that function's promise to settle before continuing. Here's theasync
example fromfor-of
usingforEach
instead — notice how there's an initial delay, but then all the text appears right away instead of waiting: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 valuesome
(spec | MDN) - stops looping the first time the callback returns a truthy valuefilter
(spec | MDN) - creates a new array including elements where the callback returns a truthy value, omitting the ones where it doesn'tmap
(spec | MDN) - creates a new array from the values returned by the callbackreduce
(spec | MDN) - builds up a value by repeatedly calling the callback, passing in previous values; see the spec for the detailsreduceRight
(spec | MDN) - likereduce
, but works in descending rather than ascending orderAs with
forEach
, if you use anasync
function as your callback, none of those waits for the function's promise to settle. That means:async
function callback is never appropriate withevery
,some
, andfilter
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.async
function callback is often appropriate withmap
, 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
, orPromise.any
).async
function callback is rarely appropriate withreduce
orreduceRight
, because (again) the callback will always return a promise. But there is an idiom of building a chain of promises from an array that usesreduce
(const promise = array.reduce((p, element) => p.then(/*...something using `element`...*/));
), but usually in those cases afor-of
orfor
loop in anasync
function will be clearer and easier to debug.3. Use a simple
for
loopSometimes the old ways are the best:
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:
And/or counting backward:
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 uselet
within thefor
to scope the variables to just the loop. And when you do that, theindex
variable is recreated for each loop iteration, meaning closures created in the loop body keep a reference to theindex
for that specific iteration, which solves the old "closures in loops" problem: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 oflet
(you'd always see "Index is: 5").Like
for-of
,for
loops work well inasync
functions. Here's the earlier example using afor
loop:4. Use
for-in
correctlyfor-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:Looking only at that first example: You can use
for-in
to visit those sparse array elements if you use appropriate safeguards:Note the three checks:
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 addsObject.hasOwn
which can be more reliable), andThat the name is all decimal digits (e.g., normal string form, not scientific notation), and
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:
Like
for
,for-in
works well in asynchronous functions if the work within it needs to be done in series.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: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 propertyvalue
with the value for that iteration. (done
is optional if it would befalse
,value
is optional if it would beundefined
.)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 provide0
, then1
, then2
(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 inasync
function loops. Here's the earlierfor-of
example using the iterator explicitly: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, thearguments
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:
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 fromgetElementsByXYZ
methods andNodeList
s instances fromquerySelectorAll
both support iteration. (This is defined quite subtly by the HTML and DOM specifications. Basically, any object withlength
and indexed access is automatically iterable. It doesn't have to be markediterable
; that is used only for collections that, in addition to being iterable, supportforEach
,values
,keys
, andentries
methods.NodeList
does;HTMLCollection
doesn't, but both are iterable.)Here's an example of looping through
div
elements:Use
forEach
and related (ES5+)The various functions on
Array.prototype
are "intentionally generic" and can be used on array-like objects viaFunction#call
(spec | MDN) orFunction#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 aNode
'schildNodes
collection (which, being anHTMLCollection
, doesn't haveforEach
natively). You'd do this:(Note, though, that you could just use
for-of
onnode.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.:
Use a simple
for
loopPerhaps obviously, a simple
for
loop works for array-like objects.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:
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:...takes the
NodeList
fromquerySelectorAll
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:
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):So for instance, if we want to convert a
NodeList
into a true array, with spread syntax this becomes quite succinct:Use the
slice
method of arraysWe 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:So for instance, if we want to convert a
NodeList
into a true array, we could do this:(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.)注意:这个答案已经过时了。如需更现代的方法,请查看数组。感兴趣的方法可能是:
在 JavaScript 是一个普通的 for 循环:
但是请注意,只有当您有一个密集数组并且每个索引都被一个元素占用时,这种方法才有效。如果数组是稀疏的,那么使用这种方法可能会遇到性能问题,因为您将迭代数组中实际上不存在的大量索引。在这种情况下,
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:
The standard way to iterate an array in JavaScript is a vanilla
for
-loop: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 thefor..in
-loop will also be enumerated in legacy browsers, or if the additional properties are defined asenumerable
.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.
如果您使用 jQuery 库,则可以使用 jQuery.each:
编辑:
根据问题,用户需要代码在 javascript 而不是 jquery 中,所以编辑是
If you’re using the jQuery library, you can use jQuery.each:
EDIT :
As per question, user want code in javascript instead of jquery so the edit is
向后循环
我认为 反向 for 循环值得在这里提及:
优点:
len
变量,或与array.length< 进行比较/code> 每次迭代,其中任何一个都可能是微小的优化。
array[i]
处的项目),然后前向循环将跳过向左移动到位置 i 的项目,或重新处理 i > 右移的第一项。在传统的 for 循环中,您可以更新i以指向需要处理的下一个项目 - 1,但简单地反转迭代方向通常更简单 和 更优雅的解决方案。forEach()
和 ES6 的for ... of
。缺点:
我应该始终使用它吗?
一些开发人员默认使用反向 for 循环,除非有充分的理由向前循环。
虽然性能提升通常微不足道,但它有点令人尖叫:
然而在实践中,这实际上不是可靠的意图指示,因为它与您确实关心订单的情况没有区别,并且确实需要反向循环。因此,实际上需要另一个构造来准确表达“不关心”的意图,目前大多数语言(包括 ECMAScript)都无法实现这一点,但可以调用它,例如
forEachUnordered()
。如果顺序并不重要,并且需要考虑效率(在游戏或动画引擎的最内层循环中),那么使用反向 for 循环作为首选模式可能是可以接受的。请记住,在现有代码中看到反向 for 循环并不一定意味着顺序无关!
最好使用 forEach()
一般来说,对于更高级别的代码,其中清晰度和安全性更受关注,我之前建议使用
Array::forEach
作为循环的默认模式(尽管现在我更喜欢使用for..of
)。优先使用forEach
而不是反向循环的原因是:for
和while
循环中的惊喜)。然后,当您在代码中看到反向 for 循环时,这暗示它是有充分理由被反转的(可能是上述原因之一)。看到传统的前向循环可能表明可以发生移位。
(如果意图的讨论对您来说毫无意义,那么您和您的代码可能会受益于观看 Crockford 的讲座 编程风格和你的大脑。)
现在使用 for..of 甚至更好!
关于
for..of
还是forEach()
哪个更可取存在争议:为了获得最大的浏览器支持,
for..of
迭代器需要一个polyfill,使您的应用执行速度稍微慢一些要下载更大的文件。出于这个原因(并鼓励使用
map
和filter
),一些前端样式指南完全禁止for..of
!但上述问题不适用于 Node.js 应用程序,其中
for..of
现在得到了很好的支持。此外
await
在forEach 中不起作用
()
。使用for..of
是最清晰的模式 在这种情况下。就我个人而言,我倾向于使用看起来最容易阅读的内容,除非性能或缩小已成为主要问题。所以这些天我更喜欢使用
for..of
而不是forEach()
,但我总是会使用map
或filter< /code> 或
查找
或some
时适用的。(为了同事的利益,我很少使用
减少
。)它是如何工作的?
您会注意到
i--
是中间子句(我们通常在其中看到比较),最后一个子句为空(我们通常在其中看到i++
)。这意味着i--
也用作继续的条件。至关重要的是,它在每次迭代之前执行和检查。它如何从
array.length
开始而不爆炸?因为
i--
在每次迭代之前运行,所以在第一次迭代时,我们实际上将访问array.length - 1
处的项目这避免了Array-out-of-boundsundefined
项的任何问题。为什么它在索引 0 之前不停止迭代?
当条件
i--
计算结果为假值时(当它产生 0 时),循环将停止迭代。诀窍在于,与
--i
不同,尾随的i--
运算符会递减i
但产生值 在减量之前。您的控制台可以演示这一点:<代码>>变量我 = 5; [i,i--,i];
<代码>[5,5,4]
因此,在最后一次迭代中,i 之前为 1,
i--
表达式将其更改为 0 > 但实际上产生 1 (真值),因此条件通过。在下一次迭代中,i--
将i更改为-1,但产生0(错误),导致执行立即从循环底部掉出。在传统的前向 for 循环中,
i++
和++i
是可以互换的(正如 Douglas Crockford 指出的那样)。然而,在反向 for 循环中,因为我们的减量也是我们的条件表达式,所以如果我们想要处理索引 0 处的项目,我们必须坚持使用i--
。琐事
有些人喜欢画一个小箭头在反向
for
循环中,并以眨眼结束:感谢 WYL 向我展示了反向 for 循环的优点和缺点。
Loop backwards
I think the reverse for loop deserves a mention here:
Advantages:
len
variable, or compare againstarray.length
on each iteration, either of which might be a minute optimisation.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.forEach()
and to ES6'sfor ... of
.Disadvantages:
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:
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 usefor..of
). Reasons to preferforEach
over a reverse loop are:for
andwhile
loops).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
orforEach()
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
andfilter
), some front-end style guides banfor..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 insideforEach()
. Usingfor..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 offorEach()
, but I will always usemap
orfilter
orfind
orsome
when applicable.(For the sake of my colleagues, I rarely use
reduce
.)How does it work?
You will notice that
i--
is the middle clause (where we usually see a comparison) and the last clause is empty (where we usually seei++
). That means thati--
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 atarray.length - 1
which avoids any issues withArray-out-of-boundsundefined
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 trailingi--
operator decrementsi
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 iterationi--
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 withi--
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:Credits go to WYL for showing me the benefits and horrors of the reverse for loop.
一些 C 风格语言使用
foreach
进行循环枚举。在 JavaScript 中,这是通过for..in< 完成的/code> 循环结构
:
有一个问题。
for..in
将循环访问对象的每个可枚举成员及其原型上的成员。为了避免读取通过对象原型继承的值,只需检查该属性是否属于该对象:此外, ECMAScript 5 添加了
forEach
到Array.prototype
的方法,可用于使用回调枚举数组(polyfill 在文档中,因此您仍然可以在旧版浏览器中使用它):需要注意的是,当回调返回
false
时,Array.prototype.forEach
不会中断。 jQuery 和 Underscore.js 在each
上提供了自己的变体,以提供可以短路的循环。Some C-style languages use
foreach
to loop through enumerations. In JavaScript this is done with thefor..in
loop structure: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:Additionally, ECMAScript 5 has added a
forEach
method toArray.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):It's important to note that
Array.prototype.forEach
doesn't break when the callback returnsfalse
. jQuery and Underscore.js provide their own variations oneach
to provide loops that can be short-circuited.为...的| 对于每个| map
使用现代 JavaScript 语法来迭代数组
for...of | forEach | map
Using modern JavaScript syntax to iterate through arrays
???????? for...of
???????? forEach
???????? map
*Different from the two above, map() creates a new array and expects you to return something after each iteration.
???? Important: As map() is meant to return a value at each iteration, it is an ideal method for transforming elements in arrays:
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:
如果要循环数组,请使用标准的三部分
for
循环。您可以通过缓存
myArray.length
或向后迭代来获得一些性能优化。If you want to loop over an array, use the standard three-part
for
loop.You can get some performance optimisations by caching
myArray.length
or iterating over it backwards.如果您不介意清空数组:
x
将包含y
的最后一个值,并将其从数组中删除。您还可以使用shift()
来给出和删除y
中的第一项。If you don't mind emptying the array:
x
will contain the last value ofy
and it will be removed from the array. You can also useshift()
which will give and remove the first item fromy
.forEach 实现(参见 jsFiddle):
A forEach implementation (see in jsFiddle):
我知道这是一篇旧帖子,并且已经有很多很好的答案。为了更完整一点,我想我应该使用 AngularJS 添加另一个。当然,这仅适用于您使用 Angular 的情况,显然,尽管如此我还是想把它说出来。
angular.forEach 采用 2 个参数和一个可选的第三个参数。第一个参数是要迭代的对象(数组),第二个参数是迭代器函数,可选的第三个参数是对象上下文(在循环内基本上称为“this”)。
使用 forEach 有不同的方法最简单也可能最常用的是
将项目从一个数组复制到另一个数组的另一种方法是
,但您不必这样做,您可以简单地执行以下操作,它与前面的示例等效:
现在各有利弊使用
angular.forEach
函数而不是内置的普通for
循环优点
>angular.forEach
将使用 ES5 forEach 循环。现在,我将在缺点部分讨论效率,因为 forEach 循环比我提到的 for 循环慢得多。专业人士因为保持一致和标准化是件好事,请考虑以下两个嵌套循环,它们执行完全相同的操作。假设我们有 2 个对象数组,每个对象都包含一个结果数组,每个结果都有一个 Value 属性,该属性是字符串(或其他内容)。假设我们需要迭代每个结果,如果它们相等,则执行一些操作:
当然这是一个非常简单的假设示例,但我已经使用第二种方法编写了三重嵌入 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
Another way that is useful for copying items from one array to another is
Though, you don't have to do that, you can simply do the following and it's equivalent to the previous example:
Now there are pros and cons of using the
angular.forEach
function as opposed to the built in vanilla-flavoredfor
loop.Pros
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:
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
angular.forEach
, and the nativeforEach
, for that matter, are both so much slower than the normalfor
loop....about 90% slower. So for large data sets, best to stick to the nativefor
loop.continue
is actually supported by "accident", to continue in anangular.forEach
you simple put areturn;
statement in the function likeangular.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 nativeforEach
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 anangular.forEach
in that bad boy.自 ECMAScript 6 起:
其中
of
避免了与in
相关的奇怪现象,并使其像任何其他语言的for
循环一样工作,而let
> 在循环内而不是在函数内绑定i
。当只有一个命令时(例如上例中),可以省略大括号 (
{}
)。As of ECMAScript 6:
Where
of
avoids the oddities associated within
and makes it work like thefor
loop of any other language, andlet
bindsi
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).可能 for(i = 0; i < array.length; i++) 循环不是最佳选择。为什么?如果有这样的情况:
该方法将从
array[0]
调用到array[2]
。首先,这将首先引用您甚至没有的变量,其次,您在数组中不会有这些变量,第三,这将使代码更加大胆。看这里,这就是我使用的:如果你希望它是一个函数,你可以这样做:
如果你想打破,多一点逻辑:
示例:
它返回:
Probably the
for(i = 0; i < array.length; i++)
loop is not the best choice. Why? If you have this:The method will call from
array[0]
toarray[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:And if you want it to be a function, you can do this:
If you want to break, a little more logic:
Example:
It returns:
jQuery 中有
foreach
的三种实现,如下所示。There are three implementations of
foreach
in jQuery as follows.现在一个简单的解决方案是使用 underscore.js 库。它提供了许多有用的工具,例如
each
,并且会自动将作业委托给本机forEach
(如果可用)。CodePen 示例说明其工作原理:
另请参阅
Array.prototype.forEach()
的文档。对于每个(对象中的变量)
作为 ECMA-357 的一部分已被弃用(EAX)标准。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 nativeforEach
if available.A CodePen example of how it works is:
See also
Array.prototype.forEach()
.for each (variable in object)
is deprecated as the part of ECMA-357 (EAX) standard.for (variable of object)
as the part of the Harmony (ECMAScript 6) proposal.原生 JavaScript 中没有任何
for every
循环。您可以使用库来获取此功能(我推荐 Underscore.js),使用简单的for
in 循环。但是,请注意,可能有理由使用更简单的
for
循环(请参阅 Stack Overflow 问题为什么在数组迭代中使用“for...in”是一个坏主意吗?)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 simplefor
in loop.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?)ECMAScript 5(JavaScript 版本)处理数组:
forEach - 迭代数组中的每个项目,并对每个项目执行您需要的操作。
如果您对使用某些内置功能对数组进行操作更感兴趣。
map - 它使用回调函数的结果创建一个新数组。当您需要格式化数组元素时,可以很好地使用此方法。
reduce - 顾名思义,它通过调用传入当前元素和先前执行结果的给定函数将数组减少为单个值。
every - 如果数组中的所有元素都通过回调函数中的测试,则返回 true 或 false。
filter - 与 every 非常相似,只是过滤器返回一个数组,其中的元素对给定函数返回 true。
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.
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.
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.
every - Returns true or false if all the elements in the array pass the test in the callback function.
filter - Very similar to every except that filter returns an array with the elements that return true to the given function.
在 JavaScript 中,有几种方法可以循环遍历数组,如下所示:
for - 这是最常见的方法。用于循环的完整代码块
while - 当条件满足时循环。这似乎是最快的循环
do/while - 在条件为真时也循环执行一段代码,至少运行一次
功能循环 -
forEach
、map
、filter
以及reduce
(它们循环函数,但如果您需要对数组执行某些操作等,则会使用它们。有关数组函数式编程的更多信息和示例,请参阅博客文章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
while - loop while a condition is through. It seems to be the fastest loop
do/while - also loop through a block of code while the condition is true, will run at least one time
Functional loops -
forEach
,map
,filter
, alsoreduce
(they loop through the function, but they are used if you need to do something with your array, etc.For more information and examples about functional programming on arrays, look at the blog post Functional programming in JavaScript: map, filter and reduce.
这是一个非稀疏列表的迭代器,其中索引从 0 开始,这是处理 document.getElementsByTagName 或 document.querySelectorAll 时的典型场景)
使用示例:
示例 #1< /strong>
示例 #2
每个 p 标签都会获得
class="blue"
示例 #3
每个其他 p 标签都会获得
class="red"
>示例 #4
最后,前 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)
Examples of usage:
Example #1
Example #2
Each p tag gets
class="blue"
Example #3
Every other p tag gets
class="red"
>Example #4
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.
尽可能使用
for...of
async
/await
支持为...的
Use
for...of
where possibleasync
/await
supportfor...of
forEach()
for...in
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
See
for...of
reference for more examples, link to specification and difference betweenfor...of
andfor...in
. Or maybe check this tutorial for some explanation on how they differ.forEach
中没有内置的中断功能。要中断执行,请使用Array#some
,如下所示:这是有效的,因为只要按数组顺序执行的任何回调返回 true,
some
就会返回 true,从而短路其余的执行。原始答案
请参阅一些的数组原型
There's no inbuilt ability to break in
forEach
. To interrupt execution use theArray#some
like below: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
我还想将其添加为反向循环的组合,并为也喜欢这种语法的人提供上面的答案。
优点:
这样做的好处是:您已经在第一行中获得了引用,以后不需要在另一行中声明。循环对象数组时它很方便。
缺点:
只要引用为 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.
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.
使用
$.map
的 jQuery 方式:jQuery way using
$.map
:将循环与 ECMAScript 6 解构 和展开运算符
事实证明,展开运算符的解构和使用对于 ECMAScript 6 的新手来说非常有用,因为它更具人类可读性/美观性,尽管一些 JavaScript 老手可能会认为它凌乱的。青少年或其他一些人可能会发现它很有用。
示例 1: 普通
for...of
循环 - 这里没有技巧。示例 2:将单词拆分为字符
示例 3:使用
key
和value
进行循环示例 4: 内联获取对象属性
示例 5:获取所需的深层对象属性
示例 6:示例 3 是否与
.forEach
一起使用示例 7: 示例 4 是否与
.forEach
一起使用示例 8: 示例 5 是否与
.forEach
一起使用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.
Example 1: Normal
for...of
loop - no tricks here.Example 2: Split words to characters
Example 3: Looping with a
key
andvalue
Example 4: Get object properties inline
Example 5: Get deep object properties of what you need
Example 6: Is Example 3 used with
.forEach
Example 7: Is Example 4 used with
.forEach
Example 8: Is Example 5 used with
.forEach
摘要:
在迭代数组时,我们通常希望实现以下目标之一:
我们希望迭代数组并创建一个新数组:
Array.prototype.map
我们想要迭代数组并且不创建新数组:
Array.prototype.forEach
for..of
loop在 JavaScript 中,有很多方法可以实现这两个目标。然而,有些比其他更方便。下面你可以找到一些常用的方法(我认为是最方便的)在 JavaScript 中完成数组迭代。
创建新数组:
Map
map()
是位于Array.prototype
上的函数,它可以转换数组的每个元素,然后返回一个 <强>新数组。map()
将回调函数作为参数,并按以下方式工作:我们作为参数传递给
map()
的回调将针对每个元素执行。然后返回一个与原始数组长度相同的数组。在此新数组元素中,通过作为参数传递给map()
的回调函数进行转换。map
与另一种循环机制(例如forEach
和for..of
循环)之间的明显区别在于map 返回一个新数组并保持旧数组完好无损
(除非您使用类似于
splice
的方式显式操作它)。另请注意,
map
函数的回调提供当前迭代的索引号作为第二个参数。此外,第三个参数是否提供了调用map
的数组?有时这些属性非常有用。使用
forEach
进行循环forEach
是一个位于Array.prototype
上的函数,它接受回调函数作为参数。然后它对数组中的每个元素执行此回调函数。与map()
函数相反,forEach 函数不返回任何内容 (undefined
)。例如:就像
map
函数一样,forEach
回调提供当前迭代的索引号作为第二个参数。另外,第三个参数是否提供了调用forEach
的数组?使用
for..of
循环遍历元素for..of
循环循环遍历数组(或任何其他可迭代对象)的每个元素。它按以下方式工作:在上面的例子中,
element
代表数组元素,arr
是我们要循环的数组。请注意,名称element
是任意的,我们可以选择任何其他名称,例如“el”或在适用时更具声明性的名称。不要将
for..in
循环与for..of
循环混淆。for..in
将循环遍历数组的所有可枚举属性,而for..of
循环将仅循环遍历数组元素。例如:Summary:
When iterating over an array, we often want to accomplish one of the following goals:
We want to iterate over the array and create a new array:
Array.prototype.map
We want to iterate over the array and don't create a new array:
Array.prototype.forEach
for..of
loopIn 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 onArray.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: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 tomap()
.The distinct difference between
map
and another loop mechanism likeforEach
and afor..of
loop is thatmap
returns a new array and leaves the old array intact (except if you explicitly manipulate it with thinks likesplice
).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 whichmap
was called? Sometimes these properties can be very useful.Loop using
forEach
forEach
is a function which is located onArray.prototype
which takes a callback function as an argument. It then executes this callback function for every element in the array. In contrast to themap()
function, the forEach function returns nothing (undefined
). For example:Just like the
map
function, theforEach
callback provides the index number of the current iteration as a second argument. Also, does the third argument provide the array on whichforEach
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:In the above example,
element
stands for an array element andarr
is the array which we want to loop. Note that the nameelement
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 thefor..of
loop.for..in
will loop through all enumerable properties of the array whereas thefor..of
loop will only loop through the array elements. For example:今天
(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 慢很多倍,但是对于小型数组,可以使用它 - 为了提高代码清晰度。缓存在
n
(Ab、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 元素)进行测试,并将它们分为三组:
for
测试while
测试跨浏览器结果
所有测试浏览器的结果
浏览器**
包含 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 introducen
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:
for
testswhile
testsCross browser results
Results for all tested browsers
browsers**
Array with 10 elements
Results for Chrome. You can perform the test on your machine here.
Array with 1,000,000 elements
Results for Chrome. You can perform the test on your machine here
最接近您想法的方法是使用 Array.forEach() ,它接受一个将为数组的每个元素执行的闭包函数。
另一种可行的方法是使用 Array.map() ,它的工作方式相同,但它也会获取您返回的所有值并将它们返回到一个新数组中(本质上将每个元素映射到一个新的数组)一),像这样:
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.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:根据新的更新功能 ECMAScript 6 (ES6) 和 ECMAScript 2015,您可以将以下选项与循环一起使用:
As per the new updated feature ECMAScript 6 (ES6) and ECMAScript 2015, you can use the following options with loops:
lambda 语法通常不适用于 Internet Explorer 10 或更低版本。
我通常使用
如果您是 jQuery 粉丝并且已经运行了 jQuery 文件,则应该反转索引和值参数的位置
The lambda syntax doesn't usually work in Internet Explorer 10 or below.
I usually use the
If you are a jQuery fan and already have a jQuery file running, you should reverse the positions of the index and value parameters
您可以像这样调用 forEach:
forEach
将迭代您提供的数组,并且对于每次迭代,它将有element
保存该迭代的值。如果您需要索引,您可以通过将i
作为 forEach 回调函数中的第二个参数传递来获取当前索引。Foreach 基本上是一个高阶函数,它接受另一个函数作为其参数。
输出:
您还可以像这样迭代数组:
You can call forEach like this:
forEach
will iterate over the array you provide and for each iteration it will haveelement
which holds the value of that iteration. If you need index you can get the current index by passing thei
as the second parameter in the callback function for forEach.Foreach is basically a High Order Function, Which takes another function as its parameter.
Output:
You can also iterate over an array like this:
如果你想使用
forEach()
,它会看起来像 -如果你想使用
for()
,它会看起来像 -If you want to use
forEach()
, it will look like -If you want to use
for()
, it will look like -