Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSHint won't let me use 'forEach' in a 'for' loop

I have an object with arrays as values.

people = {
    'steve':['foo','bar'],
    'joe':['baz','boo']
}

For each key, I would like to loop over the values in the corresponding array. Simple enough:

for ( var person in people ) {
    person.forEach( function(item) {
      console.log(item)
    })
}

But JSHint complains:

Don't make functions within a loop.

Is this truly an issue with my code? I quite like the short ES5 for loop syntax. Do I need to use the ES3 style or change my code in some other way?

like image 347
mikemaccana Avatar asked May 04 '12 15:05

mikemaccana


1 Answers

There are two issues there, the one that JSHint is warning you about, and a more fundamental one.

The thing that JSHint is warning you about is that in theory, every time that loop runs, a new function is created. This would be better:

for ( var person in people ) {
    person.forEach(handlePerson);
}
function handlePerson(item) {
  console.log(item)
}

I say "in theory" because although the spec requires that a new function object be created each time, that doesn't mean engines can't reuse the underlying implementation of the function, and it doesn't mean that engines can't reuse the same function object if you didn't assign any other properties to it or keep a reference to it. I asked the V8 guys about it (V8 being the JavaScript engine in Chrome), and they said that Chrome will "...in most cases..." reuse the underlying function implementation for different function objects created at the same point in the source code, and that they would "expect" that most other engines would do the same.

So JSHint may be being a bit over-the-top in this particular case. But it's frequently a useful warning, particularly if the functions you're creating inside the loop refer to variables whose contents change during the loop, which is the classic closure error people make.

But more fundamentally, person is a String (it's the name of a property in people), and String doesn't have forEach. You wanted:

for ( var person in people ) {
    people[person].forEach(handlePerson);
}
function handlePerson(item) {
  console.log(item)
}

...e.g., people[person] to get the array for that key.

like image 102
T.J. Crowder Avatar answered Oct 15 '22 15:10

T.J. Crowder