Подтвердить что ты не робот

Параметр уловлен JavaScript уже определен

Я пытаюсь понять, почему я получаю следующую ошибку, а не как ее обойти.

Передача следующего кода в JSLint или JSHint дает ошибку "err" уже определено.

/*jslint white: true, devel: true, onevar: true, browser: true, undef: true, nomen: true, regexp: true, plusplus: true, windows: true, bitwise: true, newcap: true, strict: true, maxerr: 50, indent: 4 */
function xyzzy() {

    "use strict";

    try { /*Step 1*/ } catch (err) { }
    try { /*Step 2*/ } catch (err) { }

}

Очевидное предположение здесь состоит в том, что catch ведет себя или должно вести себя как функция. Таким образом, err не является глобальной переменной или локальной переменной для xyzzy, а параметром для блока catch.

При просмотре ECMA-262 Standard, раздел 12.14, описывающий инструкцию try указывает, что предложение catch принимает идентификатор, привязанный к исключению. Кроме того, правило семантического производства для catch относится к параметру, который передал вызывной идентификатор в качестве аргумента.

Это, по-видимому, подсказывает случайному читателю, что приведенный выше код действителен и что, возможно, в инструментах lint есть ошибка.

Даже IntelliJ строгий анализ проверки кода JavaScript не сообщает об этом проблема с переопределением err.

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

/*jslint white: true, devel: true, onevar: true, browser: true, undef: true, nomen: true, regexp: true, plusplus: true, windows: true, bitwise: true, newcap: true, strict: true, maxerr: 50, indent: 4 */
function xyzzy() {

    "use strict";
    var err;  // DECLARE err SO IT IS CERTAINLY LOCAL

    try { /*Step 1*/ } catch (err) { }
    try { /*Step 2*/ } catch (err) { }

}

Но это приводит только к двум ошибкам о err в каждом из операторов catch, что делает проблему хуже и потенциально представляет затенением переменных.

Инструменты lint показывают, что каждый блок catch вводит не только его собственную лексическую область, но и новую переменную. Это не может быть правильно.

Простое создание err1, err2,... для успокоения инструментов статического анализа просто скрывает симптом и не способствует созданию более чистого кода.

Гугеры JavaScript. Является ли это ошибкой в ​​инструменте lint, темном углу с спецификацией JavaScript или фундаментальном непонимании того, что происходит здесь?

ОБНОВЛЕНИЕ: Написал Douglas Crockford, автору JSLint, и, оказывается, есть очень веская причина для этого предупреждения. См. Ответ ниже.

4b9b3361

Ответ 1

Написал Дуглас Крокфорд, автор JSLint, об этой проблеме.

В конце концов, оказывается, очень важная причина...

Дуглас пишет:

Перемещаемые переменные не отображаются правильно, поэтому я рекомендую вам использовать другое имя в каждом из них.

Если вы посмотрите на fooobar.com/questions/180010/..., вы заметите, что PleaseStand начал касаться этого. Не все браузеры, особенно исторические, обрабатывают область видимости правильно или последовательно.

JSLint распознает, что ваш код может работать в одном браузере, но не в другом, оставляя очень неприятную и тонкую ошибку для отслеживания. Предупреждение реально.

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

Спасибо Дугласу за разъяснение! Тайна решена.

Ответ 2

В спецификации достаточно ясно, что любое имя, определяемое оператором catch, будет ничего, кроме теневого окружающего имени. Кроме того, я бы не рассматривал эти ошибки как не что иное, как предупреждение. Просто используя чистую интуицию, я считаю, что это просто чрезмерный анализ со стороны дизайнера этих инструментов Линта.

Поскольку блок catch вводит новую область, одноименное имя просто затеняет любые похожие имена в охватывающей области. Это не обязательно плохо, если вы знаете о семантике. Если вы кодируете в предположении, что приложение err будет доступно, чем вам нужно будет изменить свои предположения.

Спецификация

Производственный блок Catch: catch (Identifier) ​​оценивается следующим образом:

  • Пусть C - это параметр, который был передан этой продукции.
  • Пусть oldEnv - это исполняемые контексты выполнения LexicalEnvironment.
  • Пусть catchEnv будет результатом вызова NewDeclarativeEnvironment, передающего oldEnv в качестве аргумента.
  • Вызвать конкретный метод CreateMutableBinding для catchEnv, передав значение идентификатора String в качестве аргумента.
  • Вызвать конкретный метод SetMutableBinding для catchEnv, передавая идентификаторы, C и false в качестве аргументов. Обратите внимание, что последний аргумент в этой ситуации несуществен.
  • Задайте текущие контексты выполнения LexicalEnvironment для catchEnv.
  • Пусть B - результат оценки блока.
  • Установите текущие контексты выполнения LexicalEnvironment на oldEnv.
  • Возврат B.

ПРИМЕЧАНИЕ Независимо от того, как элемент управления оставляет блок, LexicalEnvironment всегда восстанавливается в прежнее состояние.

Ответ 3

Отметьте этот ответ: JSLint жалуется на мой try/catch

Как уже упоминалось, try открывает новый блок-область. См. https://developer.mozilla.org/en/JavaScript/Reference/Scope_Cheatsheet

Действительно, верхняя часть документа объясняет, что это не все стандартное, но в ES5, раздел 12.14 раздел о выполнении catch блок четко определяет описание MDC как стандартное:

Независимо от того, как элемент управления покидает блок, LexicalEnvironment всегда восстанавливается до прежнего состояния.

Ответ 4

У вас может возникнуть проблема с повторным использованием одного и того же имени параметра при последовательных попытках, если впоследствии вам понадобится обратиться к ошибке.

Если было вызвано более одного улова, только последнее будет доступно для выражения finally или функции.

jsLint консервативен - если вы можете предотвратить зависание с уникальной переменной, почему бы не использовать его?