Parametr catch JavaScript już zdefiniowany

Próbuję zrozumieć dlaczego dostaję następujący błąd, a nie Jak to obejść.

Przekazanie następującego kodu JSLint lub JSHint daje błąd 'err' jest już zdefiniowany.

/*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) { }

}

Oczywistym założeniem jest tutaj, że catch zachowuje się, lub powinien zachowywać się, jak funkcja. Tak więc err nie jest zmienną globalną, ani zmienną lokalną do xyzzy, ale parametrem dla catch blok.

W przeglądaniu standardu ECMA-262 , sekcja 12.14 opisująca oświadczenie try wskazuje, że klauzula catch przyjmuje identyfikator , który jest związany do wyjątku. Dodatkowo reguła produkcji semantycznej dla catch odnosi się do parametru , który jest przekazywany wywołując identyfikator jako argument .

Wydaje się to sugerować przypadkowemu czytelnikowi, że powyższy kod jest ważny i że być może narzędzia lint mają błąd.

Nawetścisła Analiza kodu JavaScript IntelliJ nie zgłasza problemu z redefinicją err.

Jeśli chodzi o zmienny zakres, to można przypuszczać, że err wykrwawia się w przestrzeni globalnej, co stwarza cały szereg innych problemów, a zamiast tego należy zadeklarować to z góry, jak to: {[20]]}
/*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) { }

}

Ale to skutkuje teraz tylko dwoma błędami o {[3] } przy każdym ze stwierdzeń catch, co pogarsza problem i potencjalnie wprowadza zmienną shadowing.

Narzędzia lint sugerują, że każdy catch blok wprowadza nie tylko własny zakres leksykalny, ale także nową zmienną. To nie może być prawda.

Simply making err1, err2, ... aby udobruchać narzędzia analizy statycznej, wystarczy ukryć objaw i nie przyczynia się do czystszego kodu.

JavaScript Guru : czy to błąd w narzędzie lint, ciemny kącik ze specyfikacją JavaScript, czy fundamentalne nieporozumienie co się tutaj dzieje?

UPDATE: napisał do Douglasa Crockforda, autora JSLint, i okazało się, że jest bardzo ważny powód tego ostrzeżenia. Zobacz odpowiedź poniżej.

Author: Walt Stoneburner, 2011-05-23

4 answers

Wrote to Douglas Crockford , author of JSLint, about this issue.

Okazuje się jednak, że jest bardzo ważny powód...

Douglas pisze:

Zmienne Catch nie są poprawnie skonfigurowane, więc zalecam użycie innej nazwy w każdej z nich.

Jeśli spojrzysz na to podobne pytanie Stoskoverflow zauważysz, że PleaseStand zaczął go dotykać. nie wszystkie przeglądarki, zwłaszcza historyczne, radzić sobie z zakresami poprawnie lub konsekwentnie.

JSLint rozpoznaje, że Twój kod może działać w jednej przeglądarce, ale nie w innej, pozostawiając bardzo paskudny i subtelny błąd do wyśledzenia. Ostrzeżenie jest prawdziwe.

Używając innej nazwy, która, tak, nie wydaje się czysta ani zwięzła, ponieważ tak nie jest, zdarza się, że jest to uniwersalny sposób, aby nie wpaść w problem.

Dziękuję Douglas za Wyjaśnienie!Zagadka rozwiązana.

 10
Author: Walt Stoneburner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:35

Specyfikacja jest dość jasna, że jakakolwiek nazwa zdefiniowana w instrukcji catch nie zrobi nic więcej niż zacienienie nazwy otaczającej. Poza tym nie uważałbym tych błędów za nic więcej niż Ostrzeżenie. Po prostu używając czystej intuicji uważam, że jest to po prostu nadgorliwa analiza ze strony projektanta tych narzędzi Lint.

Ponieważ blok catch wprowadza nowy zakres, użycie tej samej nazwy spowoduje po prostu przyciemnienie podobnych nazw w otaczającym zakresie. To niekoniecznie zła rzecz, jeśli jesteś świadomy semantyki. Jeśli kodujesz przy założeniu, że enclosing err będzie dostępny, musisz zmienić swoje założenia.

Specyfikacja

Blok produkcyjny Catch : Catch ( identyfikator ) jest oceniany w następujący sposób:

  1. niech C będzie parametrem przekazanym do tej produkcji.
  2. niech oldEnv będzie środowiskiem leksykalnym kontekstu uruchamiania.
  3. niech catchEnv będzie wynikiem wywołanie NewDeclarativeEnvironment przekazujące oldEnv jako argument.
  4. wywoĹ 'a konkretnÄ ... metodÄ ™ catchEnv przekazujÄ ... cÄ ... wartoĹ" Ä ‡ ciÄ ™ gu identyfikatora jako argument.
  5. wywołaj konkretną metodę catchEnv przekazującą identyfikator, C i false jako argumenty. Zauważ, że ostatni argument jest nieistotny w tej sytuacji.
  6. Ustaw środowisko leksykalne kontekstu uruchamiania na catchEnv.
  7. niech B będzie wynikiem oceny Blok.
  8. Ustaw środowisko leksykalne kontekstu uruchamiania na oldEnv.
  9. Return B.

Notatka bez względu na to, jak kontrola opuszcza blok, środowisko leksykalne jest zawsze przywracane do poprzedniego stanu.

 3
Author: ChaosPandion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-23 16:58:37

Sprawdź tę odpowiedź: JSLint]}

Jak już wspomniano, try otwiera nowy zakres bloku. Zobacz https://developer.mozilla.org/en/JavaScript/Reference/Scope_Cheatsheet

Rzeczywiście, Góra dokumentu wyjaśnia, że nie jest to standard, ale w ES5, sekcja 12.14 sekcja o wykonywaniu bloku catch jasno definiuje opis MDC jako standard:

Bez względu na to, jak kontrola opuszcza blok, Środowisko leksykalne jest zawsze przywracane do poprzedniego stanu.

 2
Author: davin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:29:40

You can have a problem with reusing the same parameter name in sequential try-catches if you later to reference to the error.

Jeśli wywołano więcej niż jeden haczyk, tylko ostatni będzie w zakresie wyrażenia zakresu funkcji finally or.

JsLint jest konserwatywny-jeśli można zapobiec możliwemu zepsuciu unikalnej zmiennej, dlaczego jej nie użyć?

 0
Author: kennebec,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-23 17:58:45