Search code examples
javascripttypestype-coercion

When do for loops cause type coercion javascript?


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


Solution

  • 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.