0

Given the following simple piece of Javascript code:

var a = [ 1, 2, 3 ]

for ( var i in a ) {
    console.log(a[i-1], a[i], a[i+1]);
}

why does it produce the strange output below?

undefined 1 undefined
1 2 undefined
2 3 undefined

The first undefined on the first line and the last undefined on the last line are because of out-of-bounds accesses. But where do the other two undefined's come from?

Leon
  • 31,443
  • 4
  • 72
  • 97
  • This question is not a duplicate of the two other questions. It is as much about implicit conversions as it is about iterating over arrays. The problem of `i-1` working correctly while `i+1` not, has to do with how Javascript chooses to do conversions in mixed expressions, and as pointed out in my answer you can have a similar problem even without arrays. – Leon Sep 26 '18 at 13:53

1 Answers1

2

A slightly modified test case very well exposes the problem:

$ cat test.js 
var a = [ 1, 2, 3 ]

for ( var i in a ) {
    console.log(i-1, i, i+1);
    console.log(a[i-1], a[i], a[i+1]);
    console.log('--------');
}

$ nodejs test.js 
-1 '0' '01'
undefined 1 undefined
--------
0 '1' '11'
1 2 undefined
--------
1 '2' '21'
2 3 undefined
--------

So, the variable i is of string type. When using it to access the previous element, Javascript being a weakly typed language, the interpreter figures out that the expression i-1 makes sense only if i is converted to a number. To keep things fair (and programmers' lives interesting), in the expression i+1 the interpreter converts 1 to a string and treats + as concatenation, producing a key that is missing from the array (or, if the array were long enough, a wrong element would be accessed: a[11] instead of a[2], a[21] instead of a[3], etc).

In this particular case the problem comes from the incorrect way of looping over the array (if the answer to this question was not obvious to you then carefully read the excellent explanation of how to iterate over arrays in JavaScript). However it can bite you in any other situation where a variable that is supposed to be numeric actually holds a string value (for example, when parsing text data and forgetting to do the conversions).

Leon
  • 31,443
  • 4
  • 72
  • 97