5

I have recently stumbled upon the issue of using for..in loops on arrays in JavaScript.

According to the answers in this question, for..in is intended to enumerate the properties of an object, including inherited ones.

If so, why do we have the ability to define properties as non-enumerable using Object.defineProperty? Doesn't this goes against the whole intention of for..in? Or is it considered as bad practice and should be avoided?

Also, why would we want to iterate over all the properties in such a manner in the first place (i.e. using a for..in loop)? When could this come in handy?

And why not define all (Array) prototype extensions as non-enumerable and keep using for..in with arrays?

Community
  • 1
  • 1
Johan Hirsch
  • 557
  • 4
  • 21

1 Answers1

6

The problem is that there's only one namespace for object properties (ignoring the Symbol feature in ES2015 for now). There are some object properties that you do want to be enumerable, and some you don't. The properties that contain object data and relationships to other objects share that namespace with the names of methods.

The for ... in loop looks not only at the properties of the object directly involved, but also up the prototype chain. That's probably the most likely use for non-enumerable properties: the methods that you may want to put on a prototype object probably don't need to be enumerable.

To me the real reason not to use for ... in when you're iterating through the numeric-name properties of an Array instance is that there's no guarantee you'll iterate through the indexes in any particular order. Though most runtime systems do give back numeric-name properties in the obvious order, the specification for the language absolutely does not require that that be the case. By using an explicit numeric index in a plain for loop, you thereby explicitly control the iteration order.

People who write JavaScript code for use in contexts where there'll be other code running over which they have no control (think advertising-supported sites, or sites with lots of metrics tools) know that relying on built-in prototypes not to be polluted with random junk is deeply unwise. Using for ... in puts your code at the mercy of the worst coder contributing to that third-party code.

Modern implementations have Object.keys(), which returns the enumerable "own" property names of an object; that is, the names of properties directly on the object, and none from the prototype chain.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • So basically, you're saying that extending built-in prototypes with enumerable properties is bad coding, and in a world full of perfect coders it would have been perfectly legit to use for...in with arrays? If so, what about prototype.js, for example? Are they just doing it wrong? – Johan Hirsch Aug 18 '15 at 09:14
  • @JohanHirsch **No**, I am **not** saying that `for ... in` would be good to use with arrays. Please re-read the third paragraph above. Prototype.js was an ambition project, and I think that while it was a good experiment it stands as strong evidence that extending system objects isn't a great idea. Of course, now that most JavaScript environments allow for non-enumerable properties, maybe Prototype would be less of a problem. (I really liked working with Prototype when I was doing so, 8 or 9 years ago.) – Pointy Aug 18 '15 at 12:35