2

When I do this:

const foo = [0, 1, 2]

for (i = 0; i < foo.length; i ++){
    console.log(foo[i], typeof foo[i])
}

I get this:

0 number
1 number
2 number

But when I do this:

for (let item in foo){
    console.log(item, typeof item)
}

I get this:

0 string
1 string
2 string

What is going on here?? What rules would I have needed to know to predict this?

Edit: I am running Node 12.18.3

Leo Ware
  • 109
  • 4
  • 2
    [`for...in`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in) is not the same as [`for...of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of). Change the contents of the array to `["a", "b", "c"]` and you will see the difference. – 3limin4t0r Oct 28 '20 at 22:36
  • *What rules would I have needed to know to predict this?* — you would need to be a JavaScript programmer, because those things are obvious to such individuals. – Pointy Oct 28 '20 at 22:57
  • @3limin4t0r The OP isn't asking about `for...of`. – Scott Marcus Oct 28 '20 at 23:38
  • @ScottMarcus But uses a `for...in` as though it is a `for...of`, as can be seen by the expected result. – 3limin4t0r Oct 28 '20 at 23:40
  • @3limin4t0r True, but I doubt the OP has worked with `for...of` and therefore isn't aware of that fact. – Scott Marcus Oct 28 '20 at 23:42

2 Answers2

10

There's no coercion going on here. You are actually iterating two different primitive types with your two different loops.

Traditional for loops with counters, count with numbers.

for/in loops are for iterating over properties of objects. Objects have keys/properties, which are always strings. So when you are seeing 0, 1, and 2, you are seeing the strings "0", "1", and "2".

So, when you use a for/in loop on an array instance, it's enumerated by the keys of the Array object, which include the string representation of the array indexes as well as any enumerable properties of the Array instance. You can then wind up enumerating other properties of the array besides the items in it as shown here:

const foo = [0, 1, 2];

// Add a property to the array instance
foo.bar = "baz";

for (let item in foo){
  // This will log ALL the enumerable properties
  // of the object, in this case, including properties
  // that are not the array values.
  console.log(item, foo[item]);
}

Here's another way to see this. Below is an object literal being enumerated with a for/in. Note that when the literal is created the keys don't get quotes around them, yet when their type is tested (they key name, not the key value), they are reported as strings, because they implicitly are:

let obj = {
 key1: "something",
 key2: "something else",
 foo: 42,
 false: true,
 99: 100
};

for(let prop in obj){
  // Note that even the unquoted key name of 
  // false is implicitly a string, not a Boolean
  // and the 99 key is a string, not a number
  console.log(prop, "(" + typeof prop + ")", obj[prop], "(" + typeof obj[prop] + ")");
}

As stated in the docs (link above):

The for...in statement iterates over all enumerable properties of an object that are keyed by strings (ignoring ones keyed by Symbols), including inherited enumerable properties.

Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
1

You basically mixes the values of the array (first loop when you call foo[i] in the classic for) and keys / indexes of the array (when you call for ... in ....

Just try with foo = [5,6,7] and you will clearly see the difference.

for (let a in [5,6,7])
  console.log(a, typeof a)

As stated in the other answer from Scott Marcus, index are like keys and are string here.

Also note that if you want loop over all elements of an array (or enumerable), use for ... of ...:

for (let a of [5,6,7])
  console.log(a, typeof a)
Pac0
  • 21,465
  • 8
  • 65
  • 74
  • Arrays don't have keys. – Scott Marcus Oct 28 '20 at 22:28
  • 1
    Am not saying they have, but indices of keys act "like" keys, don't they @ScottMarcus? – Pac0 Oct 28 '20 at 22:29
  • The verb "keyed" is even quoted in your answer – Pac0 Oct 28 '20 at 22:30
  • The verb "keyed" in my answer comes from MDN and is used only to describe what objects have. Your answer says *"keys / indexes of the array"*, mixing keys and indexes as if they were the same thing and both applicable to arrays, which they are not. The phrase "indicies of keys" in your above comment is indicative that you miss the point. Objects don't have indicies, period. So, they can't have indicies of keys. Objects have keys. Arrays have indexes. Indexes and keys are two different things. – Scott Marcus Oct 28 '20 at 23:18
  • "Indices of keys" is a complete failure from my part indeed, my bad! And now that it is morning on my part of the globe I'm pretty sure I meant "indices of array" – Pac0 Oct 29 '20 at 07:44