Perché le clausole catch hanno il loro ambiente lessicale?

Considera il seguente estratto da ECMA-262 v5.1 (che ho visto di recente in questa domanda ):

Un ambiente lessicale è un tipo di specifica utilizzato per definire l’associazione di identificatori a specifiche variabili e funzioni basate sulla struttura di nidificazione lessicale del codice ECMAScript. Un ambiente lessicale è costituito da un record di ambiente e da un ansible riferimento null a un ambiente lessicale esterno. Solitamente un ambiente lessicale è associato ad una specifica struttura sintattica del codice ECMAScript come una dichiarazione funzione, una clausola WithStatement o una clausola Catch di un TryStatement e un nuovo ambiente lessicale viene creato ogni volta che tale codice viene valutato.

Pensavo che ciò significasse che il corpo delle clausole di catch avrebbe issato le proprie variabili come fanno le funzioni, ma a quanto pare non è questo il caso :

 var a = 1; try { console.log(x); // ReferenceError } catch(ex) { console.log(a); // 1, not undefined var a = 3; } 

Qualcuno sa perché? Inoltre, perché una clausola di catch bisogno del proprio ambiente lessicale?

Sì, le clausole di catch hanno effettivamente i loro ambienti lessicali. Scopri cosa succede quando viene valutato : ne crea uno nuovo (derivante da quello corrente) e associa l’identificatore di eccezione ad esso. Quando si esegue il blocco catch, il LexicalEnvironment del contesto di esecuzione corrente viene passato a quello nuovo, mentre il VariableEnvironment (“il cui record di ambiente contiene i binding creati da VariableStatements e FunctionDeclarations “) rimane invariato.

 console.log(a); // undefined - declared from within the catch, // but in the current VariableEnvironment a = 1; console.log(typeof ex); // undefined - no binding try { console.log(ex); // a ReferenceError in this LexicalEnvironment } catch (ex) { // introducing the new LexicalEnvironment console.log(ex); // …and it works here! var a = 3; // variable declaration } 

Fatto divertente: se si tenta di dichiarare una funzione all’interno di una clausola catch (sebbene sintatticamente non valida in un blocco, “dichiarazioni di dichiarazione di funzione” sono spesso accettate), il suo ambito diventerà l’attuale VariableEnvironment modo che non possa accedere all’eccezione:

 try {throw "some"} catch(x) { function y(){console.log(x, typeof x);} y(); } // throws a ReferenceError for x ^ 

(Aggiornamento: questo non è più vero in ES6, dove le dichiarazioni delle funzioni a livello di blocco sono valide e si chiudono sull’ambito del blocco)