The for...of
creates a loop iterating over iterable objects (including the built-in String
, Array
, e.g. the Array
-like arguments
or NodeList
objects, TypedArray
, Map
and Set
, and user-defined iterables), invoking a custom iteration hook with statements to be executed for the value of each distinct property of the object.
for (variable of iterable) { statement }
variable
iterable
Array
let iterable = [10, 20, 30]; for (let value of iterable) { value += 1; console.log(value); } // 11 // 21 // 31
You can use const
instead of let
too, if you don't reassign the variable inside the block.
let iterable = [10, 20, 30]; for (const value of iterable) { console.log(value); } // 10 // 20 // 30
String
let iterable = 'boo'; for (let value of iterable) { console.log(value); } // "b" // "o" // "o"
TypedArray
let iterable = new Uint8Array([0x00, 0xff]); for (let value of iterable) { console.log(value); } // 0 // 255
Map
let iterable = new Map([['a', 1], ['b', 2], ['c', 3]]); for (let entry of iterable) { console.log(entry); } // ['a', 1] // ['b', 2] // ['c', 3] for (let [key, value] of iterable) { console.log(value); } // 1 // 2 // 3
Set
let iterable = new Set([1, 1, 2, 2, 3, 3]); for (let value of iterable) { console.log(value); } // 1 // 2 // 3
arguments
object(function() { for (let argument of arguments) { console.log(argument); } })(1, 2, 3); // 1 // 2 // 3
Iterating over DOM collections like NodeList
: the following example adds a read
class to paragraphs that are direct descendants of an article:
// Note: This will only work in platforms that have // implemented NodeList.prototype[Symbol.iterator] let articleParagraphs = document.querySelectorAll('article > p'); for (let paragraph of articleParagraphs) { paragraph.classList.add('read'); }
In for...of
loops, abrupt iteration termination can be caused by break
, continue[4]
, throw
or return[5]
. In these cases, the iterator is closed.
function* foo(){ yield 1; yield 2; yield 3; }; for (let o of foo()) { console.log(o); break; // closes iterator, triggers return }
You can also iterate over generators, i.e. functions generating an iterable object:
function* fibonacci() { // a generator function let [prev, curr] = [0, 1]; while (true) { [prev, curr] = [curr, prev + curr]; yield curr; } } for (let n of fibonacci()) { console.log(n); // truncate the sequence at 1000 if (n >= 1000) { break; } }
Generators should not be re-used, even if the for...of
loop is terminated early, for example via the break
keyword. Upon exiting a loop, the generator is closed and trying to iterate over it again does not yield any further results.
var gen = (function *(){ yield 1; yield 2; yield 3; })(); for (let o of gen) { console.log(o); break; // Closes iterator } // The generator should not be re-used, the following does not make sense! for (let o of gen) { console.log(o); // Never called. }
You can also iterate over an object that explicitly implements iterable protocol:
var iterable = { [Symbol.iterator]() { return { i: 0, next() { if (this.i < 3) { return { value: this.i++, done: false }; } return { value: undefined, done: true }; } }; } }; for (var value of iterable) { console.log(value); } // 0 // 1 // 2
for...of
and for...in
Both for...in
and for...of
statements iterate over something. The main difference between them is in what they iterate over.
The for...in
statement iterates over the enumerable properties of an object, in original insertion order.
The for...of
statement iterates over data that iterable object defines to be iterated over.
The following example shows the difference between a for...of
loop and a for...in
loop when used with an Array
.
Object.prototype.objCustom = function() {}; Array.prototype.arrCustom = function() {}; let iterable = [3, 5, 7]; iterable.foo = 'hello'; for (let i in iterable) { console.log(i); // logs 0, 1, 2, "foo", "arrCustom", "objCustom" } for (let i in iterable) { if (iterable.hasOwnProperty(i)) { console.log(i); // logs 0, 1, 2, "foo" } } for (let i of iterable) { console.log(i); // logs 3, 5, 7 }
Let us look into the above code step by step.
Object.prototype.objCustom = function() {}; Array.prototype.arrCustom = function() {}; let iterable = [3, 5, 7]; iterable.foo = 'hello';
Every object will inherit objCustom
property and every object that is an Array
will inherit arrCustom
property because of adding those properties to Object.prototype
and Array.prototype
. The object iterable
inherits properties objCustom
and arrCustom
because of inheritance and the prototype chain.
for (let i in iterable) { console.log(i); // logs 0, 1, 2, "foo", "arrCustom", "objCustom" }
This loop logs only enumerable properties of iterable
object, in original insertion order. It doesn't log array elements 3
, 5
, 7
or hello
because those are not enumerable properties. But it logs array indexes as well as arrCustom
and objCustom
, which are. If you're not sure why the properties are iterated over, there's a more thorough explanation of how array iteration and for...in
work.
for (let i in iterable) { if (iterable.hasOwnProperty(i)) { console.log(i); // logs 0, 1, 2, "foo" } }
This loop is similar to the first one, but it uses hasOwnProperty()
to check, if the found enumerable property is object's own (not inherited). And if it is, the property is logged. Properties 0
, 1
, 2
and foo
are logged because they are own properties (not inherited). Properties arrCustom
and objCustom
are not logged because they are inherited.
for (let i of iterable) { console.log(i); // logs 3, 5, 7 }
This loop iterates and logs values that iterable
as an iterable objectdefines to be iterated over, which are array elements 3
, 5
, 7
and not any of object's properties.
Specification | Status | Comment |
---|---|---|
ECMAScript 2015 (6th Edition, ECMA-262) The definition of 'for...of statement' in that specification. | Standard | Initial definition. |
ECMAScript Latest Draft (ECMA-262) The definition of 'for...of statement' in that specification. | Draft |
Feature | Chrome | Edge | Firefox | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|---|
Basic support | 38 | 12 | 131 | No | 25 | 8 |
Closing iterators | 51 | Yes | 53 | No | Yes | Yes |
Feature | Android webview | Chrome for Android | Edge mobile | Firefox for Android | Opera Android | iOS Safari | Samsung Internet |
---|---|---|---|---|---|---|---|
Basic support | 5.1 | Yes | 12 | Yes | 25 | 8 | ? |
Closing iterators | Yes | Yes | Yes | 53 | Yes | Yes | ? |
1. Prior to Firefox 51, using the for...of
loop construct with the const
keyword threw a SyntaxError
("missing = in const declaration").
© 2005–2018 Mozilla Developer Network and individual contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of