3

This is in Chromium 78:

for (var i in [1,3,5]) console.log(i+1)

enter image description here

Now, I expected for (var i in [1,3,5]) console.log(i+1) to output 1, 2, 3, because i should be an index value. I know the MDN docs mention that the order may come out strangely in this case, but why the type conversion?

Liam
  • 27,717
  • 28
  • 128
  • 190
Kev
  • 15,899
  • 15
  • 79
  • 112
  • 2
    `for...in` returns a string key. Also: [Why is using “for…in” with array iteration a bad idea?](https://stackoverflow.com/questions/500504) – adiga Nov 13 '19 at 13:37
  • To get the expected do `console.log(parseInt(i)+1)` – The_ehT Nov 13 '19 at 13:39
  • or just `console.log(+i+1)` – tom Nov 13 '19 at 13:39
  • 1
    Checkout the "Array iteration and for...in" section of the manual, you referenced. There is the explanation. – WuDo Nov 13 '19 at 13:40
  • 2
    Also see note section `for...in` should not be used to iterate over an Array where the index order is important" – The_ehT Nov 13 '19 at 13:40
  • 1
    That's because an array is really just a special type of object and object keys are always strings. – ibrahim mahrir Nov 13 '19 at 13:43
  • 1
    `for ... in` iterates over property keys, which are (apart from symbols) always strings... – ASDFGerte Nov 13 '19 at 13:43
  • 1
    I know it outputs a string—see title—and I know it says order is not necessarily honoured—see my post. My question was _why_. I'm also not asserting this is a best practice. – Kev Nov 13 '19 at 13:45
  • https://stackoverflow.com/questions/24077537/for-in-loop-index-is-string-instead-of-integer , https://stackoverflow.com/questions/22479386/javascript-for-loop-counter-coming-out-as-string , https://stackoverflow.com/questions/9591317/javascript-for-loop-var-i-is-treated-as-a-string , https://stackoverflow.com/questions/38985421/variable-in-for-loop-is-a-string – ASDFGerte Nov 13 '19 at 13:45
  • Thanks @ASDFGerte, I had missed that, but "why" and "what are my options for workarounds" are two different questions, so I'm still glad to have the answer here. I guess internally an Array converts its indexes back to integers before giving them back to users, but it still struck me as strange on the surface. – Kev Nov 13 '19 at 13:46
  • 1
    @Kev `Array#forEach` passes the index as a number to its callback: `[1, 3, 5].forEach((n, i) => console.log(i + 1));` – ibrahim mahrir Nov 13 '19 at 13:50
  • 1
    @Kev Actually it's the other way arround: Array internally converts the numbers (or anything really) into strings to access the property. `arr[5]` is basically `arr["5"]`. Try this: `[1, 2, 3][ { toString() { return "2"; } } ]`, first the object `{ toString() { return "2"; } }` is converted into a string which returns `"2"` which is the key of the third item in the array `[1, 2, 3]` – ibrahim mahrir Nov 13 '19 at 13:51
  • @ASDFGerte thanks for adding more. None of these came up as suggestions when posting my original question, apparently too concisely formatted for my own good (and yet people still commented without seeming to have read what I wrote in its entirety.) – Kev Nov 13 '19 at 13:54
  • 2
    The much harsher problem with `for ... in` is, that unlike many other methods (e.g. `Object.keys`), it iterates the prototype chain aswell. Therefore, e.g. `Array.prototype["surprise!"] = 1; for (let p in []) console.log(p);` may be "surprise!"'ing. – ASDFGerte Nov 13 '19 at 13:55

1 Answers1

5

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