Why Is Using "For...In" For Array Iteration a Bad Idea

Why is using for...in for array iteration a bad idea?

The reason is that one construct:

var a = []; // Create a new empty array.a[5] = 5;   // Perfectly legal JavaScript that resizes the array.
for (var i = 0; i < a.length; i++) { // Iterate over numeric indexes from 0 to 5, as everyone expects. console.log(a[i]);}
/* Will display: undefined undefined undefined undefined undefined 5*/

Why is JavaScript's For...In loop not recommended for arrays?

An array is an object, and array elements are simply properties with the numeric index converted to string. For example, arr[123] refers to a property "123" in the array object arr.

The for ... in construct works on all objects, not just arrays, and that is cause for confusion.

When somebody for ... in an array, most often the programmer intends to iterate just all the elements, even most likely in order. For example, if the array holds a bunch of numbers, then the programmer most likely intends to iterate a stream of numbers. The semantics is so similar to array iteration in other programming languages that it is very easy to get confused.

In JavaScript, this construct does not iterate array elements in order. It iterates all the array's property names (including the names of inherited prototype functions, any properties added to it, any other non-element properties added to it etc.), and not in order at all. In earlier browsers, it will even find the property length, although in recent browsers these properties are now defined to be hidden for this exact reason -- people keep tripping on it!

With the array of integers above, you get not a stream of numbers, but a stream of text strings. And not the element values, but the names of the properties (which are just the numeric indices not in any order). This is most likely not what the programmer means, if he/she comes from another programming language. If the elements stored in the array happen to be similar numeric values, it confuses the hell out of everybody.

That's why you shouldn't do it. You shouldn't use a language construct that looks like it does obvious things, but actually does things that are completely different. It creates bugs that are very obscure and very difficult to find.

Javascript: Why use a for loop instead of a for-in loop for arrays?

The issue is that some libraries (Prototype comes to mind) extend the array type, so when you use a for in loops, it hits all of the enumerable properties on that array, which includes all elements of the array, but also all added on properties or methods. Not what you want to have happen.

The for i in loop iterates only over the elements of the array, that is, anything you'd define literally as [1, 2, 3, 4].

Why are for..in faster than for loops when looping through an array

The answer for your question is simple: for in loop was not created to deal with arrays and does additional things as well and should not be used.

The main purpose of the for-in statement is to iterate thought object's properties, not through the array. This statement will also go into the array prototype chain, iteration through inherited properties and I think you do not need this or even do not know about this.

Another funny thing that you even do not know in what order it will be iterated.

So the main thing to remember - do not use for in with arrays. Only with objects.

P.S as RobG correctly added:

A for loop will search for properties on the [[Prototype]] chain too if they aren't found on the array. E.g. a for loop over [0,,2] will search for 1 all the way to Object.prototype[[Prototype]]

For-Of Loop vs. For Loop

A bit of backnowledge to explain your question:

In Javascript, Objects (among these are Arrays) store properties in key-value pairs. That means that each assigned value has a key (the property name) to access it.
For example in

person[name] = 'Tom'

person is the Object, name the key and 'Tom' the corresponding value.

Arrays use indices (i.e. numbers) as keys:

array[5] = 10

Now, keep that in mind in the following explanation.

Let's start with the traditional for loop:

for(let i = 0; i < array.length; i++) {...}

This way of iterating over an array is the oldest of the bunch (as long as you are not using while-loops)
You'll find a corresponding way of writing a for loop in pretty much any (imperative) programming language. You'll notice, it is very explicit in the way it works. E.g. you could change the break-condition i < array.length to something else (e.g. i < array.length-1 for skipping the last position), or the step i++ (e.g. to i+=2), or start at a different index (e.g. let i = 5). You can iterate backwards instead of forwards through the array, if you want. Pretty much anything you can do in another for loop, you can do in this kind as well, if you know how.

Inside the brackets {...} you can then use i as a key to access the arrays values

Now this is all very powerful and nice, but it gets cumbersome to write every time, especially if in most of the cases you just want to iterate over an array. But luckily we have for-in:

For-in will retrieve you all the keys you have set yourself. With an array, you can use that to achieve the same result as above using

for(let i in array) {...}

Note however, that for-in is not only gonna give you the number keys from an array. It is also gonna work on other keys you have set yourself on any object:

let object = {
key1 : 'value',
key2 : 'value'
}

for(let i in object) {
console.log(i)
}

will log out 'key1' and 'key2' (yes, the keys as well are strings here).

For a bit more precise description of what keys exactly it will give you, have a look at the link below.

When would you use for-in? Whenever you want to call some code for each element of an array / (almost) each property of an object once. E.g. when you want to increment all values in an array by 1.
When not to use for-in? Don't use it if you need more granular control over the order you traverse the array in, or you don't want to hit all elements of the array, but only every second/third.

For an excellent resource on for-in loops I recommend Mozilla Developer Network

So, what are for-of loops then?

For-of loops are syntactically (i.e. the way you write them) very similar to for-in loops:

for(let v of array) {...}

However, for one, they are only going to work on so-called iterable objects (arrays are iterable). Second, you only get the values. They are no longer going to give you any keys!

let array = ['a', 'b', 'c']
for(let v of array) {
console.log(v)
}

logs 'a', 'b' and 'c'. You won't know anymore, what keys these values had!

So, when to use these? Every time you just need the values and don't care about the keys. E.g. if you just want to print the values.
When not to use them? If you want to swap elements of an array, if you want to reverse order. You can't even increment the values by 1 and store them back into the array, because for that, you would need to know their corresponding key.

For more information on for-in loops as well as what iterable actually means, again, I recommend the MDN

Why does a for ... in loop—for (var/let/const A in B)—make A a string in vanilla ES6?

i is not the index, i is the property key of the array object. Property keys are always strings.

Javascript why FOR IN is a bad practice?

Bad practice is not to understand the difference between enumerating over an array object and iterating over it. Otherwise for...in loop is excellent tool. There is big internal difference, but i will try to explain in the practical manner:

Syntax is: for (string in object), where object is an instance of Object (and, naturally, any of its descendants) and string var receives property name of object on each loop iteration. But Array is an Object descendant too! So, it is perfectly legal to use:

var array = [0,1,2];
for (var property in array)
alert(typeof property + '\t' + property + '\n' + typeof array[property] + '\t' + array[property]);

but simply makes no sense at all. Moreover, note the bracket notation above []. This is a form of membership operator and must not be confused with array element access. First requires operand of type string and second - number. Lets break example above and create array with var array = new Array(3) instead. Loop works no longer, yet array.length == 3 correctly.

Conclusion: use for...in for any objects except arrays. Use for (var number = 0; number < array.length; number++) with arrays.

By the way, JavaScript objects are similar with PHP's associative arrays (hashtables, if you insist on the proper term). Syntax is var object = {string:value,anotherName:moreStuff}. Here for...in comes handy!

Further reading



Related Topics



Leave a reply



Submit