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
The for...in
statement iterates over the enumerable properties of an object, in an arbitrary order.
Enumerable properties are those properties whose internal [[Enumerable]] flag is set to true, hence if there is any enumerable property in the prototype chain, the for...in
loop will iterate on those as well.
The for...of
statement iterates over data that iterable object defines to be iterated over.
Example:
Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};
let iterable = [3, 5, 7];
for (let i in iterable) {
console.log(i); // logs: 0, 1, 2, "arrCustom", "objCustom"
}
for (let i in iterable) {
if (iterable.hasOwnProperty(i)) {
console.log(i); // logs: 0, 1, 2,
}
}
for (let i of iterable) {
console.log(i); // logs: 3, 5, 7
}
Like earlier, you can skip adding hasOwnProperty
in for...of
loops.
I found the following explanation from https://javascript.info/array very helpful:
One of the oldest ways to cycle array items is the for loop over indexes:
let arr = ["Apple", "Orange", "Pear"];
for (let i = 0; i < arr.length; i++) { alert( arr[i] ); } But for arrays there is another form of loop, for..of:
let fruits = ["Apple", "Orange", "Plum"];
// iterates over array elements for (let fruit of fruits) { alert( fruit ); } The for..of doesn’t give access to the number of the current element, just its value, but in most cases that’s enough. And it’s shorter.
Technically, because arrays are objects, it is also possible to use for..in:
let arr = ["Apple", "Orange", "Pear"];
for (let key in arr) { alert( arr[key] ); // Apple, Orange, Pear } But that’s actually a bad idea. There are potential problems with it:
The loop for..in iterates over all properties, not only the numeric ones.
There are so-called “array-like” objects in the browser and in other environments, that look like arrays. That is, they have length and indexes properties, but they may also have other non-numeric properties and methods, which we usually don’t need. The for..in loop will list them though. So if we need to work with array-like objects, then these “extra” properties can become a problem.
The for..in loop is optimized for generic objects, not arrays, and thus is 10-100 times slower. Of course, it’s still very fast. The speedup may only matter in bottlenecks. But still we should be aware of the difference.
Generally, we shouldn’t use for..in for arrays.
for..in
and for..of
:Both for..in
and for..of
are looping constructs which are used to iterate over data structures. The only difference between them is the entities
they iterate over:
for..in
iterates over all enumerable property keys of an objectfor..of
iterates over the values of an iterable object. Examples of iterable objects are arrays, strings, and NodeLists.let arr = ['el1', 'el2', 'el3'];
arr.addedProp = 'arrProp';
// elKey are the property keys
for (let elKey in arr) {
console.log(elKey);
}
// elValue are the property values
for (let elValue of arr) {
console.log(elValue)
}
In this example we can observe that the for..in
loop iterates over the keys of the object, which is an array object in this example. The keys are 0, 1, 2 (which correspond to the array elements) and addedProp
. This is how the arr
array object looks in chrome devtools:
You see that our for..in
loop does nothing more than simply iterating over these keys.
The for..of
loop in our example iterates over the values of a data structure. The values in this specific example are 'el1', 'el2', 'el3'
. The values which an iterable data structure will return using for..of
is dependent on the type of iterable object. For example an array will return the values of all the array elements whereas a string returns every individual character of the string.
The for...in loop improves upon the weaknesses of the for loop by eliminating the counting logic and exit condition.
Example:
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const index in digits) {
console.log(digits[index]);
}
But, you still have to deal with the issue of using an index to access the values of the array, and that stinks; it almost makes it more confusing than before.
Also, the for...in loop can get you into big trouble when you need to add an extra method to an array (or another object). Because for...in loops loop over all enumerable properties, this means if you add any additional properties to the array's prototype, then those properties will also appear in the loop.
Array.prototype.decimalfy = function() {
for (let i = 0; i < this.length; i++) {
this[i] = this[i].toFixed(2);
}
};
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const index in digits) {
console.log(digits[index]);
}
Prints:
0
1
2
3
4
5
6
7
8
9
function() { for (let i = 0; i < this.length; i++) { this[i] = this[i].toFixed(2); } }
This is why for...in loops are discouraged when looping over arrays.
NOTE: The forEach loop is another type of for loop in JavaScript. However, forEach() is actually an array method, so it can only be used exclusively with arrays. There is also no way to stop or break a forEach loop. If you need that type of behavior in your loop, you’ll have to use a basic for loop.
The for...of loop is used to loop over any type of data that is iterable.
Example:
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const digit of digits) {
console.log(digit);
}
Prints:
0
1
2
3
4
5
6
7
8
9
This makes the for...of loop the most concise version of all the for loops.
But wait, there’s more! The for...of loop also has some additional benefits that fix the weaknesses of the for and for...in loops.
You can stop or break a for...of loop at anytime.
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const digit of digits) {
if (digit % 2 === 0) {
continue;
}
console.log(digit);
}
Prints:
1
3
5
7
9
And you don’t have to worry about adding new properties to objects. The for...of loop will only loop over the values in the object.
for in loops over enumerable property names of an object.
for of (new in ES6) does use an object-specific iterator and loops over the values generated by that.
In your example, the array iterator does yield all the values in the array (ignoring non-index properties).
The for-in statement iterates over the enumerable properties of an object, in arbitrary order.
The loop will iterate over all enumerable properties of the object itself and those the object inherits from its constructor's prototype
You can think of it as "for in" basically iterates and list out all the keys.
var str = 'abc';
var arrForOf = [];
var arrForIn = [];
for(value of str){
arrForOf.push(value);
}
for(value in str){
arrForIn.push(value);
}
console.log(arrForOf);
// ["a", "b", "c"]
console.log(arrForIn);
// ["0", "1", "2", "formatUnicorn", "truncate", "splitOnLast", "contains"]