On 2011-11-11, at 9:21 AM, Erick Lavoie wrote:
Le 11-11-10 23:46 , Bruno Dufour a écrit :
On 2011-11-10, at 7:18 PM, Erick Lavoie wrote:
Running the following code in v8 I get:
0 var f = 0;
1
2 (function ()
3 {
4 try
5 {
6 throw 1;
7 } catch (f)
8 {
9 print(f); // print 1
10 f = 2;
11 print(f); // print 2
12 }
13 print(f); // print 0
14 })();
However, replacing line 11 by
var f = 2;
will print 'undefined' at line 13 instead of '0'. Which
means that
although catch introduces a lexical binding for f, a var
statement with
the same name inside a catch block introduces a local
variable spanning
the whole function. However, the assignation is still made
on the
variable local to the catch statement!
I'll look at the standard to understand how this could be
explained.
The explanation is simple. A catch introduces a new scope
where the identifier of the thrown exception is a mutable
binding. So, the assignments to f behave as you observed.
However, the spec also states that the outer scope of the
catch will be restored as to its original state after the
execution of the catch:
"No matter how control leaves the Block the
LexicalEnvironment is always restored to its former state."
(ES5 spec, p97)
So,
in the first case, 0 is printed because is bound to the
global, which had the value 0 before the catch. In the
second, f is bound to the local var, which was of course
undefined before the catch.
Bruno
Right. Still, the surprising thing about this behavior is that the
"var f = 2;" statement implicitly refers to two different
variables. The first one is in the function scope and is being
created because of the presence of a "var" declaration. The second
one is local to the catch block and is the target of all accesses
and assignments within this scope. Although this statement can
introduce a new variable at the function scope, there is no way to
access the created variable in the catch scope.
The var declaration gets floated to the top of the *variable* environment (the function scope in this case), not the lexical environment created for the catch. But, the lexical scope is used first to resolve names, so as you point out, the var isn't accessible at all inside of the catch because it is shadowed by the exception id.
In comparison, a "var f = 2;" statement outside a catch block will
refer to a single variable, being both created at the function scope
and assigned in the statement.
Well, this difference between variable envs and lexical envs is indeed a little ugly, but isn't it supposed to disappear in ES6 when lexical scoping gets applied across the board? (I haven't read the new proposal yet...)
Having a single statement with a single identifier refer to two
logical variables is somewhat confusing.
Agreed. A 'var x = y' is conceptually a 'var x; x = y;' where the effect of the first part can be seen before the statement itself. But, this is true in other JS constructs as well and somewhat of an orthogonal issue IMHO.
Bruno