ES3.1 Draft: 11 June 2008 version available
Brendan Eich
brendan at mozilla.org
Mon Jun 16 10:49:09 PDT 2008
On Jun 16, 2008, at 8:39 AM, Mark S. Miller wrote:
> On Sat, Jun 14, 2008 at 11:43 PM, Garrett Smith
> <dhtmlkitchen at gmail.com> wrote:
>> The spec doesn't mention that FunctionExpression with Identifier can
>> affect scope chain. Example:-
>>
>> (function f() {
>> var propertyIsEnumerable = 0;
>> (function f() {
>> alert(propertyIsEnumerable); //=> native code
>> })();
>> })();
>
>
> Hi Garrett, thanks for alerting us to this bizarre behavior. I had no
> idea.
Lars included it in "Compatibility Between ES3 and Proposed ES41",
section 1.6, although the example there shows only the catch variable
case. IIRC, Pratap pointed the problem out well over a year ago, but
I can't find the reference at the moment.
> I did reproduce this behavior and minor variants. However,
> oether variants didn't work, indicating that I don't yet understand
> what's happening here. For example, on Firefox 2.0.0.14 in squarefree:
>
> var g = function f() { return x; }
>
> g()
> ReferenceError on line 1: x is not defined
>
> g.x = 3;
> 3
>
> g()
> ReferenceError on line 1: x is not defined
>
> As I thought I understood this example, I would have expected the last
> call to g() to return 3. Can someone explain why it doesn't?
Ad-hoc properties on the function object do not show up as variables
referenced lexically, the bug is different. ES3 says (13, third
production's semantics):
The production FunctionExpression : function Identifier
( FormalParameterListopt ) { FunctionBody } is evaluated as follows:
1. Create a new object as if by the expression new Object().
2. Add Result(1) to the front of the scope chain.
3. Create a new Function object as specified in section 13.2 with
parameters specified by FormalParameterListopt and body specified by
FunctionBody. Pass in the scope chain of the running execution
context as the Scope.
4. Create a property in the object Result(1). The property's name is
Identifier, value is Result(3), and attributes are { DontDelete,
ReadOnly }.
5. Remove Result(1) from the front of the scope chain.
6. Return Result(3).
Therefore one bad case for a named function expression goes like this:
js> var g = function f(){return x}
js> Object.prototype.x = 'wrong'
wrong
js> var x = 'right'
js> g()
wrong
Garrett showed an example using a standard property of
Object.prototype, propertyIsEnumerable.
Worse, the ES3 spec says "as if by the expression new Object()". So
by the book, one could do this (doesn't work in Firefox, Opera,
perhaps others who wisely ignore the spec):
js> var fake = {x:'fake'}
js> Object = function(){return fake}
js> var g = function f(){return x}
js> g()
fake
but you would need to be careful to restore Object to
fake.constructor or equivalent before going too far.
http://wiki.ecmascript.org/doku.php?id=clarification:which_prototype
talks about the inconsistencies in ES3 between "original value
of ..." and "as if by the expression".
/be
More information about the Es4-discuss
mailing list