JSHint не позволит мне использовать 'forEach' в цикле 'for'

У меня есть объект с массивами как значения.

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

Для каждой клавиши я хотел бы перебрать значения в соответствующем массиве. Достаточно просто:

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

Но JSHint жалуется:

Don't make functions within a loop.

Это действительно проблема с моим кодом? Мне очень нравится короткий синтаксис ES5 для цикла. Нужно ли использовать стиль ES3 или изменить свой код каким-либо другим способом?

Ответ 1

Есть две проблемы: одна, о чем предупреждает JSHint, и более фундаментальный.

О том, что JSHint предупреждает вас о том, что теоретически каждый раз работает цикл, создается новая функция. Это было бы лучше:

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

Я говорю "теоретически", потому что, хотя спецификация требует, чтобы каждый новый объект функции создавался каждый раз, это не означает, что двигатели не могут повторно использовать базовую реализацию функции, и это не означает, что двигатели могут Повторное использование одного и того же объекта функции, если вы не присвоили ему никаких других свойств или не сохранили ссылку на него. Я спросил об этом ребята V8 (V8 был движком JavaScript в Chrome), и они сказали, что Chrome будет "... в большинстве случаев..." повторно использовать реализация базовых функций для разных объектов функций, созданных в одной и той же точке исходного кода, и что они "ожидают", что большинство других движков будут делать то же самое.

Таким образом, JSHint может быть немного выше, чем в этом конкретном случае. Но часто это полезное предупреждение, особенно если функции, которые вы создаете в цикле, относятся к переменным, содержимое которых изменяется во время цикла, что является классической ошибкой закрытия, которую делают люди.

Но более принципиально person является String (это имя свойства в people), а String не имеет forEach. Вы хотели:

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

... например, people[person], чтобы получить массив для этого ключа.

Ответ 2

В дополнение к другим комментаторам, если вы знаете, что делаете, вы можете отключить это предупреждение с помощью опции JSHint loopfunc:

/*jshint loopfunc:true */

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

Вы можете установить параметры JSHint глобально (если вы используете модуль NPM), для каждого файла или для каждой функции.

Ответ 3

Вы можете использовать forEach внутри цикла, но вам не разрешено объявлять функцию внутри цикла.

function looper (item) {
  console.log(item)
}

for ( var person in people ) {
    person.forEach(looper)
}

... в противном случае вы воссоздаете одну и ту же функцию для каждой итерации.

Ответ 4

Это не forEach, его анонимная функция, на которую он жалуется.

Ответ 5

Причина, по которой это проблема, заключается в том, что она создает новую ссылку на объект для анонимной функции внутри вызова foreach в куче каждый раз, когда вы это делаете. Было бы лучше, если бы вы назначили функцию переменной вне цикла for, таким образом вы не ели память бесполезно