Как исправить ошибку jslint «Не создавать функции внутри цикла.»? - PullRequest
60 голосов
/ 14 июня 2010

Я работаю над тем, чтобы весь наш 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 классического наследования, где классы, расширяющие существующие классы, сохраняютсупер свойство расширенного класса при вызове члена расширенного класса.Просто для пояснения, приведенная выше реализация вдохновлена ​​этим сообщением в блоге Джона Резига.

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

Единственное единственноеОбходной путь до сих пор состоит в том, чтобы исключить эти файлы JS из jslint, но мы хотели бы использовать jslint для проверки кода и проверки синтаксиса как часть нашей непрерывной интеграции и рабочего процесса сборки.

Есть ли лучший способ для реализации таких функций, какэто или есть способ настроить код с помощью jslint?

Ответы [ 6 ]

65 голосов
/ 14 июня 2010

У Дугласа Крокфорда есть новый идиоматический способ достижения вышесказанного - его старая техника заключалась в использовании внутренней функции для привязки переменных, но новая техника использует создатель функций. См. слайд 74 на слайдах к его разговору «Функция предельного» * ​​1002 *. [Этот слайдшер больше не существует]

Для ленивых вот код:

function make_handler(div_id) {
    return function () {
        alert(div_id);
    };
}
for (i ...) {
    div_id = divs[i].id;
    divs[i].onclick = make_handler(div_id);
}
12 голосов
/ 21 января 2011

(я только что наткнулся на эти вопросы спустя много месяцев после того, как он был опубликован ...)

Если вы создаете функцию в цикле, экземпляр функции создается для каждой итерации цикла.Если выполняемая функция на самом деле не отличается для каждой итерации, тогда используйте метод помещения генератора функций за пределы цикла - это не просто Crockery, это позволяет тем, кто читает ваш код, знать, что это было вашим намерением.

Если функция фактически является той же самой функцией, назначаемой различным значениям в итерации (или объектам, созданным в итерации), то вместо этого вам нужно назначить функцию именованной переменной и использовать этот единственный экземплярфункции в присваивании в цикле:

handler = function (div_id) {
    return function() { alert(div_id); }
}

for (i ...) {
    div_id = divs[i].id;
    divs[i].onclick = handler(div_id);
}

Более умные комментарии / обсуждения по этому поводу были сделаны другими умнее меня, когда я задал подобный вопрос здесь о переполнении стека: Ошибка JSlint 'Don'сделать функции внутри цикла.приводит к вопросу о самом Javascript

Что касается JSLint: Да, это догматично и идиоматично.Тем не менее, это обычно «правильно» - я обнаружил, что многие люди, которые негативно высказываются о JSLint, на самом деле не понимают (тонкости) Javascript, которые многочисленны и тупы.

10 голосов
/ 15 октября 2016

Буквально, получите вокруг проблемы, выполнив следующее:

  1. Создайте .jshintrc файл
  2. Добавьте следующую строку в ваш .jshintrc файл

    {"loopfunc" : true, // tolerate functions being defined in loops }

7 голосов
/ 14 июня 2010

JSLint - это только руководство, вам не всегда нужно соблюдать правила.Дело в том, что вы не создаете функции в цикле в том смысле, к которому они относятся.Вы создаете свои классы только один раз в своем приложении, не снова и снова.

5 голосов
/ 20 февраля 2012

Если вы используете 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);
}
3 голосов
/ 14 июня 2010

Просто переместите:

(function (name, func) {...})()

блокирует цикл и присваивает его переменной, например:

var makeFn = function(name, func){...};

Тогда в цикле есть:

prototype[prop] = makeFn(...)

...