I know what is for... in
loop (it iterates over key), but heard the first time about for... of
(it iterates over value).
I am confused with
There are some already defined data types which allows us to iterate over them easily e.g Array, Map, String Objects
Normal for in iterates over the iterator and in response provides us with the keys that are in the order of insertion as shown in below example.
const numbers = [1,2,3,4,5];
for(let number in number) {
console.log(number);
}
// result: 0, 1, 2, 3, 4
Now if we try same with for of, then in response it provides us with the values not the keys. e.g
const numbers = [1,2,3,4,5];
for(let numbers of numbers) {
console.log(number);
}
// result: 1, 2, 3, 4, 5
So looking at both of the iterators we can easily differentiate the difference between both of them.
Note:- For of only works with the Symbol.iterator
So if we try to iterate over normal object, then it will give us an error e.g-
const Room = {
area: 1000,
height: 7,
floor: 2
}
for(let prop in Room) {
console.log(prop);
}
// Result area, height, floor
for(let prop of Room) {
console.log(prop);
}
Room is not iterable
Now for iterating over we need to define an ES6 Symbol.iterator e.g
const Room= {
area: 1000, height: 7, floor: 2,
[Symbol.iterator]: function* (){
yield this.area;
yield this.height;
yield this.floors;
}
}
for(let prop of Room) {
console.log(prop);
}
//Result 1000, 7, 2
This is the difference between For in and For of. Hope that it might clear the difference.
When I first started out learning the for in and of loop, I was confused with my output too, but with a couple of research and understanding you can think of the individual loop like the following : The
let profile = {
name : "Naphtali",
age : 24,
favCar : "Mustang",
favDrink : "Baileys"
}
The above code is just creating an object called profile, we'll use it for both our examples, so, don't be confused when you see the profile object on an example, just know it was created.
So now let us use the for...in loop below
for(let myIndex in profile){
console.log(`The index of my object property is ${myIndex}`)
}
// Outputs :
The index of my object property is 0
The index of my object property is 1
The index of my object property is 2
The index of my object property is 3
Now Reason for the output being that we have Four(4) properties in our profile object and indexing as we all know starts from 0...n, so, we get the index of properties 0,1,2,3 since we are working with the for..in loop.
for...of loop* can return either the property, value or both, Let's take a look at how. In javaScript, we can't loop through objects normally as we would on arrays, so, there are a few elements we can use to access either of our choices from an object.
Object.keys(object-name-goes-here) >>> Returns the keys or properties of an object.
Object.values(object-name-goes-here) >>> Returns the values of an object.
Below are examples of their usage, pay attention to Object.entries() :
Step One: Convert the object to get either its key, value, or both.
Step Two: loop through.
// Getting the keys/property
Step One: let myKeys = ***Object.keys(profile)***
Step Two: for(let keys of myKeys){
console.log(`The key of my object property is ${keys}`)
}
// Getting the values of the property
Step One: let myValues = ***Object.values(profile)***
Step Two : for(let values of myValues){
console.log(`The value of my object property is ${values}`)
}
When using Object.entries() have it that you are calling two entries on the object, i.e the keys and values. You can call both by either of the entry. Example Below.
Step One: Convert the object to entries, using ***Object.entries(object-name)***
Step Two: **Destructure** the ***entries object which carries the keys and values***
like so **[keys, values]**, by so doing, you have access to either or both content.
// Getting the keys/property
Step One: let myKeysEntry = ***Object.entries(profile)***
Step Two: for(let [keys, values] of myKeysEntry){
console.log(`The key of my object property is ${keys}`)
}
// Getting the values of the property
Step One: let myValuesEntry = ***Object.entries(profile)***
Step Two : for(let [keys, values] of myValuesEntry){
console.log(`The value of my object property is ${values}`)
}
// Getting both keys and values
Step One: let myBothEntry = ***Object.entries(profile)***
Step Two : for(let [keys, values] of myBothEntry){
console.log(`The keys of my object is ${keys} and its value
is ${values}`)
}
Make comments on unclear parts section(s).
A see a lot of good answers, but I decide to put my 5 cents just to have good example:
iterates over all enumerable props
let nodes = document.documentElement.childNodes;
for (var key in nodes) {
console.log( key );
}
iterates over all iterable values
let nodes = document.documentElement.childNodes;
for (var node of nodes) {
console.log( node.toString() );
}
for-in
loopfor-in
loop is used to traverse through enumerable properties of a collection, in an arbitrary order. A collection is a container type object whose items can be using an index or a key.
var myObject = {a: 1, b: 2, c: 3};
var myArray = [1, 2, 3];
var myString = "123";
console.log( myObject[ 'a' ], myArray[ 1 ], myString[ 2 ] );
for-in
loop extracts the enumerable properties (keys) of a collection all at once and iterates over it one at a time. An enumerable property is the property of a collection that can appear in for-in
loop.
By default, all properties of an Array and Object appear in for-in
loop. However, we can use Object.defineProperty method to manually configure the properties of a collection.
var myObject = {a: 1, b: 2, c: 3};
var myArray = [1, 2, 3];
Object.defineProperty( myObject, 'd', { value: 4, enumerable: false } );
Object.defineProperty( myArray, 3, { value: 4, enumerable: false } );
for( var i in myObject ){ console.log( 'myObject:i =>', i ); }
for( var i in myArray ){ console.log( 'myArray:i =>', i ); }
In the above example, the property d
of the myObject
and the index 3
of myArray
does not appear in for-in
loop because they are configured with enumerable: false
.
There are few issues with for-in
loops. In the case of Arrays, for-in
loop will also consider methods
added on the array using myArray.someMethod = f
syntax, however, myArray.length
remains 4
.
for-of
loopIt is a misconception that for-of
loop iterate over the values of a collection. for-of
loop iterates over an Iterable
object. An iterable is an object that has the method with the name Symbol.iterator
directly on it one on one of its prototypes.
Symbol.iterator
method should return an Iterator. An iterator is an object which has a next
method. This method when called return value
and done
properties.
When we iterate an iterable object using for-of
loop, the Symbol.iterator
the method will be called once get an iterator object. For every iteration of for-of
loop, next
method of this iterator object will be called until done
returned by the next()
call returns false. The value received by the for-of
loop for every iteration if the value
property returned by the next()
call.
var myObject = { a: 1, b: 2, c: 3, d: 4 };
// make `myObject` iterable by adding `Symbol.iterator` function directlty on it
myObject[ Symbol.iterator ] = function(){
console.log( `LOG: called 'Symbol.iterator' method` );
var _myObject = this; // `this` points to `myObject`
// return an iterator object
return {
keys: Object.keys( _myObject ),
current: 0,
next: function() {
console.log( `LOG: called 'next' method: index ${ this.current }` );
if( this.current === this.keys.length ){
return { done: true, value: null }; // Here, `value` is ignored by `for-of` loop
} else {
return { done: false, value: _myObject[ this.keys[ this.current++ ] ] };
}
}
};
}
// use `for-of` loop on `myObject` iterable
for( let value of myObject ) {
console.log( 'myObject: value => ', value );
}
The for-of
loop is new in ES6 and so are the Iterable and Iterables. The Array
constructor type has Symbol.iterator
method on its prototype. The Object
constructor sadly doesn't have it but Object.keys()
, Object.values()
and Object.entries()
methods return an iterable (you can use console.dir(obj)
to check prototype methods). The benefit of the for-of
loop is that any object can be made iterable, even your custom Dog
and Animal
classes.
The easy way to make an object iterable is by implementing ES6 Generator instead of custom iterator implementation.
Unlike for-in
, for-of
loop can wait for an async task to complete in each iteration. This is achieved using await
keyword after for
statement documentation.
Another great thing about for-of
loop is that it has Unicode support. According to ES6 specifications, strings are stored with UTF-16 encoding. Hence, each character can take either 16-bit
or 32-bit
. Traditionally, strings were stored with UCS-2 encoding which has supports for characters that can be stored within 16 bits
only.
Hence, String.length
returns number of 16-bit
blocks in a string. Modern characters like an Emoji character takes 32 bits. Hence, this character would return length
of 2. for-in
loop iterates over 16-bit
blocks and returns the wrong index
. However, for-of
loop iterates over the individual character based on UTF-16 specifications.
var emoji = "
Another difference between the two loops, which nobody has mentioned before:
Destructuring
for...in
is deprecated. Usefor...of
instead.
Source
So if we want to use destructuring in a loop, for get both index and value of each array element, we should to use the for...of
loop with the Array method entries():
for (const [idx, el] of arr.entries()) {
console.log( idx + ': ' + el );
}
I find a complete answer at : https://www.typescriptlang.org/docs/handbook/iterators-and-generators.html (Although it is for type script, this is same for javascript too)
Both
for..of
andfor..in
statements iterate over lists; the values iterated on are different though,for..in
returns a list of keys on the object being iterated, whereasfor..of
returns a list of values of the numeric properties of the object being iterated.Here is an example that demonstrates this distinction:
let list = [4, 5, 6]; for (let i in list) { console.log(i); // "0", "1", "2", } for (let i of list) { console.log(i); // "4", "5", "6" }
Another distinction is that
for..in
operates on any object; it serves as a way to inspect properties on this object.for..of
on the other hand, is mainly interested in values of iterable objects. Built-in objects likeMap
andSet
implementSymbol.iterator
property allowing access to stored values.let pets = new Set(["Cat", "Dog", "Hamster"]); pets["species"] = "mammals"; for (let pet in pets) { console.log(pet); // "species" } for (let pet of pets) { console.log(pet); // "Cat", "Dog", "Hamster" }