Confusion about different [[Scope]] between Function Declaration and Function Expression
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 Wirfs-Brock wrote:
Some implementations bind the function name scoped to the block others bind the name scoped to the enclosing function.
Detailed aside: no standard implementation actually binds to a block scope (yet -- this is proposed for ES6 and implementations are appearing, e.g. under a flag in V8 in Chrome).
Rather, the implementations bind the function "sub-statement" by its name in the outer function's activation but either always, as if hoisted independent of control flow (last in source order among several for the same name wins), or (SpiderMonkey in Firefox, Rhino, possibly others) binding the name as if by assignment if and only if control flow reaches the nested function declaration.
Web content relies on the intersection semantics. E.g.,
function outer() { ... if (cond) { function inner() { ... } obj.callback = inner; } ... }
Fortunately, ES6's block-scoped semantics for functions declared in blocks is in this intersection.
(Resending on behalf of 张立理 <otakustay at live.com> because his mail
didn't go through.)
According to section 13 Function Definition 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, 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:
If I understand correctly, here are 2 facts:
with
statement, the VariableEnvironment and LexicalEnvironment refer to the same object, here we name itouterEnv
.with
statement, we have a new LexicalEnvironment (object environment), the VariableEnvironment stays the same, here we name the new LexicalEnvironmentinnerEnv
.The problem lies in the 2 direct
eval
calls. Without the strict flag, theeval
function shares the same LexicalEnvironment and VariableEnvironment as its calling context. When theeval
is invoked in awith
statement, VariableEnvironment and LexicalEnvironment are different, so we expectfoo
andbar
outputs different numbesr:foo
should output1
andbar
should output2
.The fact is, the edge version of Chrome, Firefox and IE7-10, all output
2
and2
.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:Thanks.
Gray Zhang
电子邮件:otakustay at live.com 微博:@otakustay 博客:otakustay.com