ECMAScript 5.1 does not syntactically permit a FunctionDeclaration to directly 
appear nested within a Block.  The semantics provided by the specification are 
those for a function declaration at the top level of a function.  The only 
standard way to evaluate a function declaration within a nested lexical 
environment (established by either a with statement or a catch clause) is via a 
direct eval.  Direct eval uses the normal semantics for binding 
FunctionDeclaration so the function binds to the top level of the enclosing 
function.

Most ECMAScript implementation are extended (beyond what is in the standard) to 
allow a FunctionDeclaration to appear within a nested scope.  While this 
syntactic extension is common, there isn't a single common semantics for the 
extension.  Some implementations bind the function name scoped to the block 
others bind the name scoped to the enclosing function. Regardless, if an 
implementation supports inner scope syntactic FunctionDeclarations is makes 
sense that they would use the same semantics if the FunctionDeclaration is 
introduced via a direct eval call.  That is presumably what you are observing.

There may be a reasonable argument to be made that ES5.1 should be scoping such 
inner scope direct eval introduced FunctionDeclaration to the inner scope.  Or, 
that ES5.1 should not allow such declaration to be introduced via direct eval. 
However, the point will soon be moot as ES6 will allow inner scoped 
FunctionDeclarations and will provided a standard semantics that scopes them to 
the immediately inclosing scope.

Allen



On Dec 11, 2012, at 11:03 PM, Kang-Hao (Kenny) Lu wrote:

> (Resending on behalf of 张立理 <otakus...@live.com> because his mail
> didn't go through.)
> 
> According to [section 13 Function
> Definition](http://ecma-international.org/ecma-262/5.1/#sec-13) of
> ECMAScript-262 5.1, the **Function Declaration** production and the
> **Function Expression** production are nearly the same, except when they
> are in the process of [Create Function
> Objects](http://ecma-international.org/ecma-262/5.1/#sec-13.2), in which
> case they pass different **Scope** argument: Function Declaration passes
> the **VariableEnvironment** while Function Expression passes the
> **LexicalEnvironment**. This confuses me a little.
> 
> 
> Suppose we have this code:
> 
> 
>    function test() {
>        var x = 1;
>        var o = { x: 2 };
>        with (o) {
>            eval('function foo() { console.log(x); }');
>            eval('var bar = function() { console.log(x); }');
>        }
>        foo();
>        bar();
>    }
>    test();
> 
> 
> If I understand correctly, here are 2 facts:
> 
> 
> - outside `with` statement, the **VariableEnvironment** and
> **LexicalEnvironment** refer to the same object, here we name it `outerEnv`.
> - inside `with` statement, we have a new **LexicalEnvironment** (object
> environment), the **VariableEnvironment** stays the same, here we name
> the new **LexicalEnvironment** `innerEnv`.
> 
> 
> The problem lies in the 2 direct `eval` calls. Without the **strict**
> flag, the `eval` function shares the same **LexicalEnvironment** and
> **VariableEnvironment** as its calling context. When the `eval` is
> invoked in a `with` statement, **VariableEnvironment** and
> **LexicalEnvironment** are different, so we expect `foo` and `bar`
> outputs different numbesr: `foo` should output `1` and `bar` should
> output `2`.
> 
> 
> The fact is, the edge version of Chrome, Firefox and IE7-10, all output
> `2` and `2`.
> 
> 
> Why is ECMAScript-262 5.1 documenting a behavior that's different from
> nearly all modern browsers? Should these browsers consider their
> implementations buggy, or should our standard change a little? Anyway, I
> could not image a situation when **Function Declaration** and **Function
> Expression** should use different objects as their `[[Scope]]` internal
> property, why not use **LexicalEnvironment** of its calling context as
> all browsers do?
> 
> 
> The `catch` statement has the same problem:
> 
> 
>    function test() {
>        var x = 1;
>        try {
>            throw 2;
>        }
>        catch (x) {
>            eval('function foo() { console.log(x); }');
>            eval('var bar = function() { console.log(x); }');
>        }
>        foo();
>        bar();
>    }
>    test();
> 
> 
> Thanks.
> 
> 
> 
> Gray Zhang
> -------------
> 电子邮件:otakus...@live.com
> 微博:@otakustay
> 博客:http://otakustay.com
> _______________________________________________
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
> 

_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to