Confusion about different [[Scope]] between Function Declaration and Function Expression

Allen Wirfs-Brock allen at wirfs-brock.com
Thu Dec 13 09:12:50 PST 2012


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 张立理 <otakustay at 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
> -------------
> 电子邮件:otakustay at live.com
> 微博:@otakustay
> 博客:http://otakustay.com
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
> 



More information about the es-discuss mailing list