Я работаю над тем, чтобы весь наш JS-код проходил через 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?

62
Ernelli 14 Июн 2010 в 17:33

5 ответов

Лучший ответ

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

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

function make_handler(div_id) {
    return function () {
        alert(div_id);
    };
}
for (i ...) {
    div_id = divs[i].id;
    divs[i].onclick = make_handler(div_id);
}
65
havlock 22 Окт 2017 в 16:20

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

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

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

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, которые являются многочисленными и тупыми.

12
Community 23 Май 2017 в 12:26

Если вы используете 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);
}
5
jevon 20 Фев 2012 в 00:36

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

7
Evan Trimboli 14 Июн 2010 в 13:40

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

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

Заблокировать цикл и назначить его переменной, например:

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

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

prototype[prop] = makeFn(...)

3
TheCarver 18 Июл 2016 в 09:50