Параметр перехвата JavaScript уже определен - PullRequest
20 голосов
/ 23 мая 2011

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

Передача следующего кода в 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 , раздел 12.14, описывающий Оператор try указывает, что предложение catch принимает Идентификатор , то есть связано с исключением. Кроме того, семантическое правило производства для catch относится к параметру , который передается, вызывая идентификатор в качестве аргумента .

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

Даже Самый строгий анализ проверки кода JavaScript в IntelliJ не сообщает о проблеме переопределения 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 Gurus : Это ошибка в инструменте lint, темный угол со спецификацией JavaScript или фундаментальное недопонимание того, что здесь происходит?

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

Ответы [ 4 ]

10 голосов
/ 23 мая 2011

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

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

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

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

Если вы посмотрите на этот похожий вопрос StackOverflow , вы заметите, что PleaseStand начал касаться его. Не все браузеры, особенно исторические, обрабатывают область правильно или согласованно.

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

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

Спасибо, Дуглас, за разъяснения! Загадка раскрыта.

3 голосов
/ 23 мая 2011

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

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

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

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

  1. Позвольте C быть параметром, который был передан в эту продукцию.
  2. Пусть oldEnv будет LexicalEnvironment контекста выполнения.
  3. Пусть catchEnv будет результатом вызова NewDeclarativeEnvironment, передав в качестве аргумента oldEnv.
  4. Вызовите конкретный метод CreateMutableBinding для catchEnv, передав в качестве аргумента значение Identifier String.
  5. Вызовите конкретный метод SetMutableBinding дляcatchEnv, передав Идентификатор, C и false в качестве аргументов.Обратите внимание, что последний аргумент в этой ситуации несущественен.
  6. Установите для LexicalEnvironment контекста выполнения значение catchEnv.
  7. Пусть B будет результатом вычисления блока.
  8. Установите выполнениеLexicalEnvironment контекста выполнения для oldEnv.
  9. Возврат B.

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

2 голосов
/ 23 мая 2011

Проверьте этот ответ: JSLint жалуется на мою попытку / поймать

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

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

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

0 голосов
/ 23 мая 2011

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

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

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

...