for ... in vs for ... of
Differences
The values iterated on the
for ... in
andfor ... of
statements are different.for ... in
iterates over the enumerable property keys of object. Whereasfor ... of
iterates over the values of the numeric properties of object.const list = ['a', 'b', 'c'];
for (let i in list) {
console.log(i); // '0', '1', '2'
}
for (let i of list) {
console.log(i); // 'a', 'b', 'c'
}Unlike
for ... in
,for ... of
does not support plain objects:const person = {
firstName: 'Foo',
lastName: 'Bar',
age: 42,
};
// TypeError: `person` is not iterable
for (let k of person) {
...
}It is because a plain object is not iterable. To fix that, we can use the
Object.keys()
method to iterate on the object properties:for (let k of Object.keys(person)) {
console.log(k, ':', person[k]);
}
// firstName: Foo
// lastName: Bar
// age: 42for ... of
supports iterating over a Unicode string.const msg = 'Hellπ Wπrld';
// for ... in
for (let i in msg) {
console.log(msg[i]);
}
// Output:
// 'H', 'e', 'l', 'l', 'οΏ½', ' ', 'W', 'οΏ½', 'οΏ½', 'r', 'l', 'd'
// for ... of
for (let c of msg) {
console.log(c);
}
// Output:
// 'H', 'e', 'l', 'l', 'π', ' ', 'W', 'π', 'r', 'l', 'd'for ... of
loop can wait for an async task to complete in each iteration via theawait
keyword:for await (... of ...) {
...
}
Good practices
It is not recommended to add a custom method to primitive objects such as
Array
,Boolean
,Number
,String
, etc. Sincefor ... in
statement loops over the enumerable properties, it will include new methods which are added to the prototype.Array.prototype.isEmpty = function () {
return (this.length = 0);
};
const a = ['cat', 'dog', 'mouse'];
for (let i in a) {
console.log(i); // '0', '1', '2', 'isEmpty'
}Destructing
for ... in
is deprecated. Instead, usefor ... of
:const addressBook = new Map();
addressBook.set('Foo', '111-222-333');
addressBook.set('Bar', '444-555-666');
for (const [name, phone] of addressBook) {
console.log(name, ':', phone);
}
// Foo: 111-222-333
// Bar: 444-555-666
Good to know
By default, all properties of an array or object will appear in for ... in
. However, this behavior is avoidable. Using Object.defineProperty
can decide whether a property is enumerable or not.
let person = {
firstName: 'Foo',
lastName: 'Bar',
};
// The 'age' property is not enumerable
Object.defineProperty(person, 'age', {
value: 42,
enumerable: false,
});
for (let i in person) {
console.log(i); // 'firstName', 'lastName'
}