3

I tested the following code:

arr = [3, 5, 7];

arr.foo = "hello";

arr["boo"] ="moo"


for (i in arr) {
   console.log(i);
}

for (i of arr) {
   console.log(i); 
}

for .. in gets all the properties of the array.

for (i in arr) {
   console.log(i); 
}

returns:

0 
1 
2 
foo 
boo

but for .. of doesn't get all the values

  for (i of arr) {
       console.log(i); 
    }

returns:

3
5
7

What is the technical reason for this difference and why was this apparent inconsistency accepted as default behavior?

Eduard Florinescu
  • 13,721
  • 26
  • 101
  • 164
  • 4
    Why *would* they be the same? They're two different operators, useful for two different behaviors. – Sam Hanley Dec 07 '15 at 14:13
  • http://andrewdupont.net/2006/05/18/javascript-associative-arrays-considered-harmful/ – Bergi Dec 07 '15 at 15:36
  • @Bergi The article covers some of my points really well. – Eduard Florinescu Dec 07 '15 at 15:51
  • @EduardFlorinescu: I can't see you were making any points :-) `for of` does not enumerate all property values, it iterates elements - which for an array are only array elements. – Bergi Dec 07 '15 at 15:53
  • @sphanley I never said or implied same, you can see if you read the title I mention properties vs values, I would have expected similar behavior but I don't imply same anywhere. – Eduard Florinescu Dec 07 '15 at 15:54
  • Related: [Why are Objects not Iterable in JavaScript?](http://stackoverflow.com/q/29886552/1048572) and [Can you make properties enumerable but not iterable in javascript?](http://stackoverflow.com/q/24877452/1048572) – Bergi Feb 02 '16 at 08:55

2 Answers2

5

The for (... in ...) syntax is available for use on any object, and will iterate over all properties of that object. More technically, this loop will iterate over any property in the object that's internally defined with its [[Enumerbale]] property set to true.

The for (... of ...) syntax is new with ES6, and is specific to collections, rather than all objects. It provides a shorthand way to iterate over the elements of a collection, rather than having to use a plain for or while loop with an index. It will iterate in this manner over any the elements of any collection that has a [Symbol.iterator] property.

This isn't an "inconsistency", they're two different operators intended to be used for two different purposes. I can understand how it might seem like doing something like arr["boo"] ="moo" would add an element to the array -- since you can access the array's elements via a similar syntax, as in arr[0]. But it's easy to confirm that those aren't the same in effect - with arr["boo"] ="moo" you're creating a property that can also be accessed by arr.boo, but attempting to access the elements of an array by, say, arr.0 would be a syntax error, because they aren't the same as properties.

Sam Hanley
  • 4,498
  • 7
  • 32
  • 56
2

You're trying to treat the array as though it were an object, or an associative array (not a thing in JavaScript).

It's an array; non-integer properties are never going to be values of the array, which is what for...of will get you.

You're adding bonus properties to the arr object, but expecting the value of arr.foo to show up in for..of would be like expecting the value of arr.length to show up.

Paul Roub
  • 35,100
  • 27
  • 72
  • 83