Ошибка JSlint «Не выполняйте функции внутри цикла». приводит к вопросу о самом Javascript



Answers

Частично это зависит от того, используете ли вы выражение функции или объявление функции . Они разные, они происходят в разное время, и они оказывают иное влияние на окружающий объем. Итак, давайте начнем с различия.

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

setTimeout(function() { ... }, 1000);

var f = function() {  ... };

var named = function bar() { ... };

(Не используйте этот последний, который называется именованным выражением функции - в реализациях есть ошибки, особенно IE .)

Напротив, это объявление функции :

function bar() { ... }

Это автономно, вы не используете результат как правое значение.

Два основных различия между ними:

  1. Выражения функции оцениваются там, где они встречаются в потоке программы. Декларации оцениваются, когда управление входит в область содержимого (например, содержащая функция или глобальная область).

  2. Имя функции (если она есть) определяется в области содержимого для объявления функции. Это не выражение функции (запрет ошибок браузера).

Ваши анонимные функции являются функциональными выражениями , и поэтому запрет интерпретаторам, выполняющим оптимизацию (что можно делать бесплатно), они будут воссозданы в каждом цикле. Таким образом, ваше использование прекрасное, если вы думаете, что реализация будет оптимизирована, но разбить его на именованную функцию имеет другие преимущества и - что важно - не стоит вам ничего. Кроме того, см . Ответ casablanca для заметки о том, почему интерпретатор не может оптимизировать воссоздание функции на каждой итерации, в зависимости от того, насколько глубоко она проверяет ваш код.

Большая проблема будет заключаться в том, что вы использовали объявление функции в цикле, тело условного и т. Д .:

function foo() {
    for (i = 0; i < limit; ++i) {
        function bar() { ... } // <== Don't do this
        bar();
    }
}

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

Для моих денег лучше всего использовать объявление одной функции, например:

function foo() {
    for (i = 0; i < limit; ++i) {
        bar();
    }

    function bar() {
        /* ...do something, possibly using 'i'... */
    }
}

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

Question

У меня есть код, который вызывает анонимные функции в цикле, что-то вроде этого псевдо-примера:

for (i = 0; i < numCards; i = i + 1) {
    card = $('<div>').bind('isPopulated', function (ev) {
        var card = $(ev.currentTarget);
        ....

JSLint сообщает об ошибке «Не выполняйте функции в цикле». Мне нравится держать мой код JSLint чистым. Я знаю, что могу переместить анонимную функцию из цикла и вызывать ее как именованную функцию. В стороне, вот мой вопрос:

Будет ли интерпретатор Javascript действительно создавать экземпляр функции для каждой итерации? Или действительно ли только один экземпляр функции «скомпилирован», и один и тот же код выполняется повторно? То есть, «предложение» JSLint для перемещения функции из цикла фактически влияет на эффективность кода?




Boo для JSLint. Это похоже на тупой инструмент на голове. Новый объект функции создается каждый раз, когда function встречается (это выражение / выражение, а не декларация - редактирование: это белая ложь. См. Ответы TJ Crowders ). Обычно это делается в цикле для закрытия и т. Д. Большая проблема заключается в создании ложных замыканий .

Например:

for (var i = 0; i < 10; i++) {
  setTimeout(function () {
    alert(i)
  }, 10)
}

Это приведет к «странному» поведению. Это не проблема «создания функции в цикле, так как не понимание правил, используемых JS для областей видимости переменных и закрытий (переменные не привязаны к закрытию, областям - контекстам выполнения - есть).

Однако вы можете создать закрытие функции. Рассмотрим этот менее удивительный код:

for (var i = 0; i < 10; i++) {
  setTimeout((function (_i) { 
    return function () {
      alert(_i)
    }
  })(i), 10)
}

о нет! Я все еще создал функцию!




Related