Как исправить ошибку jslint "Не создавать функции в цикле"?
Я работаю над тем, чтобы все наши JS-коды проходили через jslint, иногда с большой настройкой с параметрами для передачи устаревшего кода в настоящее время с намерением исправить его правильно позже.
Есть одна вещь, о которой jslint жалуется, что у меня нет рабочего места. То есть при использовании таких конструкций, мы получаем ошибку "Не выполняйте функции в цикле".
for (prop in newObject) {
// Check if we're overwriting an existing function
if (typeof newObject[prop] === "function" && typeof _super[prop] === "function" &&
fnTest.test(newObject[prop])) {
prototype[prop] = (function(name, func) {
return function() {
var result, old_super;
old_super = this._super;
this._super = _super[name];
result = func.apply(this, arguments);
this._super = old_super;
return result;
};
})(prop, newObject[prop]);
}
}
Этот цикл является частью реализации классического наследования JS, когда классы, расширяющие существующие классы, сохраняют свойство super расширенного класса при вызове члена расширенного класса.
Просто для пояснения, вышеприведенная реализация вдохновлена этим сообщением от Джона Ресига.
Но у нас также есть другие экземпляры функций, созданных в цикле.
Единственным обходным решением до сих пор является исключение этих JS файлов из jslint, но мы хотели бы использовать jslint для проверки кода и проверки синтаксиса как часть непрерывного процесса интеграции и сборки.
Есть ли лучший способ реализовать такие функции или есть способ настроить такой код через jslint?
Ответы
Ответ 1
У Дугласа Крокфорда есть новый идиоматический способ достижения вышеуказанного - его старой техникой было использование внутренней функции для привязки переменных, но в новой технике используется создатель функции. См. слайд 74 в слайдах в его разговоре "Function the Ultimate" . [Это слайд-шоу больше не существует]
Для лени, вот код:
function make_handler(div_id) {
return function () {
alert(div_id);
};
}
for (i ...) {
div_id = divs[i].id;
divs[i].onclick = make_handler(div_id);
}
Ответ 2
(Я просто наткнулся на этот вопрос спустя много месяцев после его публикации...)
Если вы выполняете функцию в цикле, экземпляр функции создается для каждой итерации цикла. Если функция, которая выполняется, на самом деле отличается для каждой итерации, тогда используйте метод помещения генератора функции вне цикла - это не просто "Посуда", она позволяет другим, кто читает ваш код, знать, что это было вашим намерением.
Если функция на самом деле является той же функцией, которой назначаются разные значения в итерации (или объектах, созданных на итерации), вместо этого вам нужно назначить функцию именованной переменной и использовать этот особый экземпляр функции в назначение в цикле:
handler = function (div_id) {
return function() { alert(div_id); }
}
for (i ...) {
div_id = divs[i].id;
divs[i].onclick = handler(div_id);
}
Большой комментарий/обсуждение об этом были сделаны другими умнее меня, когда я задал аналогичный вопрос здесь о переполнении стека:
Ошибка JSlint 'Не выполняйте функции в цикле.' приводит к вопросу о самом Javascript
Что касается JSLint:
Да, это догматично и идиоматично. Тем не менее, это, как правило, "правильно" - я обнаружил, что многие люди, которые отрицательно отзываются о JSLint, на самом деле не понимают (тонкости) Javascript, которые много и тупые.
Ответ 3
Буквально обойти проблему, выполнив следующие действия:
- Создайте файл
.jshintrc
-
Добавьте следующую строку в ваш .jshintrc
файл
{"loopfunc" : true, // tolerate functions being defined in loops }
Ответ 4
JSLint - это только руководство, вы не всегда должны придерживаться правил. Дело в том, что вы не создаете функции в цикле в том смысле, в котором это имеет место. Вы только создаете свои классы один раз в своем приложении, но не снова и снова.
Ответ 5
Если вы используете JQuery, вы можете сделать что-то вроде этого в цикле:
for (var i = 0; i < 100; i++) {
$("#button").click(function() {
alert(i);
});
}
Чтобы удовлетворить JSLint, один из способов обойти это (в JQuery 1.4.3+) использовать дополнительный аргумент данных обработчика для .click()
:
function new_function(e) {
var data = e.data; // from handler
alert(data); // do whatever
}
for (var i = 0; i < 100; i++) {
$("#button").click(i, new_function);
}
Ответ 6
Просто переместите:
(function (name, func) {...})()
заблокировать из цикла и присвоить его переменной, например:
var makeFn = function(name, func){...};
Тогда в цикле есть:
prototype[prop] = makeFn(...)