for ... in
and for ... of
statements are different.for ... in
iterates over the enumerable property keys of object. Whereas for ... 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'}
for ... in
, for ... of
does not support plain objects:const person = {firstName: 'Foo',lastName: 'Bar',age: 42,};// TypeError: `person` is not iterablefor (let k of person) {...}
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: 42
for ... of
supports iterating over a Unicode string.const msg = 'Hell😀 W😀rld';// for ... infor (let i in msg) {console.log(msg[i]);}// Output:// 'H', 'e', 'l', 'l', '�', ' ', 'W', '�', '�', 'r', 'l', 'd'// for ... offor (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 the await
keyword:for await (... of ...) {...}
Array
, Boolean
, Number
, String
, etc.
Since for ... 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'}
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
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 enumerableObject.defineProperty(person, 'age', {value: 42,enumerable: false,});for (let i in person) {console.log(i); // 'firstName', 'lastName'}