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