Firefox JS vs ECMA - am I missing something?

S

Spike

Q for the language lawyers!
Here's the code:

function f(p)
{
alert("f("+p+") with this="+this);
}

var a = [f];

a[0]("index");


-----------------------------
Shouldn't a[0]("index") invoke f with this===a, since a is the 'base'
of the reference a[0]?
It doesn't, it invokes f with (apparently) this===f.

whereas
var b = new Object;
b.m = f;
b.m("method");

invokes f with this===b.

I seem to be about 3 years late asking a question like this, but I'm
writing this Javascript compiler...
 
S

Stevo

Spike said:
Q for the language lawyers!
Here's the code:
function f(p)
{
alert("f("+p+") with this="+this);
}
var a = [f];
a[0]("index");

No. Why are you expecting it to use the base. In the call a[0]() it's
a[0] that represents this.
It doesn't, it invokes f with (apparently) this===f.

Same thing. a[0]===f
whereas
var b = new Object;
b.m = f;
b.m("method");

invokes f with this===b.

Same thing again. The object you're referencing here is b, so b is this.
 
L

Lasse Reichstein Nielsen

Spike said:
Q for the language lawyers!
Here's the code:

function f(p)
{
alert("f("+p+") with this="+this);
}

var a = [f];

a[0]("index");

I would have expected so too. And I do believe it does.
It doesn't, it invokes f with (apparently) this===f.

The string representation of "this" seems to be the string
representation of the function named "f".
We would expect it to be the string representation of "a",
which is an array containing only one element, which is
the function "f". The string representation of an array
is exactly the string representation of its elements with
commas between. For a one-element array, that's the same
as the string representation of its only element.

Try:

function f(p) {
alert("f("+p+") with this=" + typeof this + " : " + this);
}

The "typeof this" gives "object", as expected for an array, not
"function" as it would if "this" was "f".

/L
 
T

Thomas 'PointedEars' Lahn

Spike said:
Q for the language lawyers!
Here's the code:

function f(p)
{
alert("f("+p+") with this="+this);
}

var a = [f];

a[0]("index");

(I'm having a déjà vu here.)

Yes, and that is the case.
It doesn't, it invokes f with (apparently) this===f.

No. The string representation of the Array object with one element is equal
to the string representation of this element, unless you have modified the
object's toString() method. Try displaying the string representation of

this === a

or use

var toString_bak = Array.prototype.toString;

Array.prototype.toString = function()
{
return "[" + toString_bak + "]";
}

a[0]("index");

Array.prototype.toString = toString_bak;

and you'll see.


PointedEars
 
T

Thomas 'PointedEars' Lahn

Thomas said:
var toString_bak = Array.prototype.toString;

Array.prototype.toString = function()
{
return "[" + toString_bak + "]";

I meant to say something along

return "[\n" + toString_bak.call(this) + "\n]";

but you'll see the difference anyway.


PointedEars
 
J

John G Harris

Q for the language lawyers!
Here's the code:

function f(p)
{
alert("f("+p+") with this="+this);
}

var a = [f];

a[0]("index");
<snip>


If you did

var z = a[0];
z.("index");

what do you think the 'this' value will be while the function is
executing ? Why would it be different when you do

a[0]("index");

instead ?

Remember that the 'this' value is calculated by the execution engine. It
uses a very simple rule and knows nothing about the complications in
your source code.

John
 
L

Lasse Reichstein Nielsen

John G Harris said:
If you did

var z = a[0];
z.("index");

I'm guessing this is a typo and it should just be
z("index")
what do you think the 'this' value will be while the function is
executing ?

The global object.
Why would it be different when you do

a[0]("index");

instead ?

Because that is how ECMAScript is specified.

There is no real difference between the function calls
a[0]("index")
and
b.foo("index")
and you would surely expect the latter to use the value of "b" as
the "this" value for the call.

In more detail:

When you evaluate a property accessor expression, e.g, a[0] or b.foo,
the immediate result of that is actually *not* the value of that
property, but a Reference value which contain both the base object and
the property name (see ECMA 262, section 8.7).

One advantage of this way of specifying the semantics of a property
access, is that it allows the same evaluation of a[0] whether or
not it happens on the left or right hand side of an assignment, e.g.,
a[0] = a[1]
That also makes it easier to specify the "delete" operator.

When a Reference value is used as a function, the value is looked up
and called, and the base object is used as the value of "this" (except
if its an activation object, i.e., the Reference came from evaluating
a local variable, then the base object is ignored so we don't expose
activation objects).

If a non-reference value is used as a function, there is no base
object, and the "this" value of the calle will be global object (see
ECAM 262 section 11.2.3).

That means that:
a[0]("foo")
calls the function on the reference a[0] (base object is the value of
"a" and property name is "0") as a function, which causes "this" to
refer to the value of "a" inside the function body.

However (if inside a function)
var z = a[0]; // only assignes value of reference, not the reference
z("foo");
will evaluate the variable "z", which does* give a reference, but with
the activation object as base object, so the value of "this" becomes
the global object during the call.

(In the global scope, "z" will evaluate to a real reference, but with
the global object as the base object, you won't be able to see the
difference :)

Remember that the 'this' value is calculated by the execution engine. It
uses a very simple rule and knows nothing about the complications in
your source code.

Actually, it does. It's a common cause of surprise, and as such it was
probably not a wise choice, but that is how ECMAScript is specified.

/L
 
S

Spike

-----------------------------
Shouldn't a[0]("index") invoke f with this===a, since a is the 'base'
of the reference a[0]?

I would have expected so too. And I do believe it does.
It doesn't, it invokes f with (apparently) this===f.

The string representation of "this" seems to be the string
representation of the function named "f".
We would expect it to be the string representation of "a",
which is an array containing only one element, which is
the function "f". The string representation of an array
is exactly the string representation of its elements with
commas between. For a one-element array, that's the same
as the string representation of its only element.

Try:

function f(p) {
alert("f("+p+") with this=" + typeof this + " : " + this);
}

The "typeof this" gives "object", as expected for an array, not
"function" as it would if "this" was "f".

Ha! Thanks Lasse & Thomas. So I read ECMA right on CallExpressions,
but I misinterpreted my output! I even remember reading that the
string rep of a 1-element array is the string rep of the element, and
thinking "That's rather odd, I wonder how that works out in practice."
Ha ha. I adjusted my code as Thomas suggested, printing the value of
(this===a), and sure enough inside f called from a[0](), this===a.
(In FF 2 anyway) A pleasure talking to folks who really know the
spec, hope you won't mind an occasional question in a similar spirit.
 
J

John G Harris

John G Harris said:
If you did

var z = a[0];
z.("index");

I'm guessing this is a typo and it should just be
z("index")
<snip>

I must have been half asleep when I wrote that! Also, I was attacking
the wrong problem :-(

John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,145
Messages
2,570,825
Members
47,371
Latest member
Brkaa

Latest Threads

Top