f = long.chain.of.identifiers.fun error?

O

optimistx

If a function is defined deep in the object chain

long.chain.of.identifiers.fun = function () {//...}

one can define a variable f

var f =long.chain.of.identifiers.fun ;

and thus have less typing, when calling fun:

f();

instead of

long.chain.of.identifiers.fun();

I thought that these should always behave in the same way,
give the same results, and follow the same execution path
inside ...fun.

Is it so? Or is there a caveat here e.g. connected to the
reference vs value thingy?

I ask this instead of continuing to debug the situation
with FORK.Event -library of Peter Michaux, where
the success of calling of listeners seems to depend on
this.

If needed, I might set up an example later.
 
D

David Mark

If a function is defined deep in the object chain

long.chain.of.identifiers.fun = function () {//...}

Does the depth matter?
one can define a variable f

var f =long.chain.of.identifiers.fun ;
Yes.


and thus have less typing, when calling fun:

Typing is not a concern (see macros). All of those dot operations
are.
f();

instead of

long.chain.of.identifiers.fun();
Yes.


I thought that these should always behave in the same way,
give the same results, and follow the same execution path
inside ...fun.

No and two maybes. For one thing, the - this - identifier will be
different.
Is it so? Or is there a caveat here e.g. connected to the
reference vs value thingy?

I ask this instead of continuing to debug the situation
with FORK.Event -library of Peter Michaux, where
the  success of calling of listeners seems to depend on
this.

If needed, I might set up an example later.

You might do that.
 
A

Asen Bozhilov

var f =long.chain.of.identifiers.fun ;

In that lookup, if someone reference doesn't referred `object', will
be harmful. Will be produce runtime error. You must be a cautious.
 
D

Dmitry A. Soshnikov

[...]
I thought that these should always behave in the same way,
give the same results, and follow the same execution path
inside ...fun.
[...]

The first difference is that [this-value] will be different in such
calls: (a) in case of [f] it will be global object (if we're in the
function context, determinate by chain: [activation object -> null ->
global]), (b) in case of long chain with properties look up
[long.chain.of.identifiers.fun] it will be base object of reference
[long.chain.of.identifiers].

About the performance, sure the variant with [f] should be faster as
all that long property access analysis is not needed. But! In the
early versions of SpiderMonkey there was vice versa situation - the
long [long.chain.of.identifiers.fun] was *faster* than [f]. The
problem guess was in determination of [this-value] which should be the
global object.

In current versions of ECMAScript-engines (and regarding to browser-
scripting) tests shows [f] is faster than
[long.chain.of.identifiers.fun], seems, SpiderMonkey has optimized
determination of [this-value] in case of null value for [this-value].
 
R

RobG

No and two maybes.  For one thing, the - this - identifier will be
different.

For the OP's benefit, the issue of the - this - keyword can be avoided
by assigning a reference to the object that the function is a method
of rather than the function itself:

var f = long.chain.of.identifiers;
f.fun();
 
O

optimistx

RobG wrote:
....
For the OP's benefit, the issue of the - this - keyword can be avoided
by assigning a reference to the object that the function is a method
of rather than the function itself:

var f = long.chain.of.identifiers;
f.fun();

THAT helped!

The question has bothered me, although circumventing the problem had been
easy this time.

Still my fear of using 'this' remains. I ought to see a picture in front of
me about this, but I do not see yet. The mind forgets thousand word
explanations, remembers pictures. Lexical scopes and objects are easy to
draw as pictures, but jumping around with 'this' is still too adventuresome.
And finding out inside the function that 'this' is something strange is not
easy. Or is it? A general routine for a newbie:

function is_this_something_you_believe_it_should_be_or_not(){... return
wise_answer;}
 
M

Matt Kruse

Still my fear of using 'this' remains.

There has to be some assumption that your code will be used correctly.
You can't guard against stupidity.

object.func = function() { ... }
anotherobject.func = object.func;
anotherobject.func();

Now you have a whole different "this" that isn't the global object,
either.

Since you can toss around references to functions and call them in any
context, you either avoid using 'this' entirely or you trust that your
users (if there are any other than yourself) aren't going to try to
break things on purpose.

Matt Kruse
 
D

Dmitry A. Soshnikov

[...]
Still my fear of using 'this' remains. I ought to see a picture in front of
me about this, but I do not see yet.
[...]

There's nothing so hard to understand with [this-value]. First of all,
you should remember that [this-value] determinate and bind to context
*dynamicaly*.

If to describe in very simplified manner, you should remember only
four cases of call expression (that's the picture):

1. if as function: func(params) ----> this === global;
2. if as method: obj.func(params) ----> this === obj;
3. if apply/call used: func.apply(obj, [params]), func.call(obj,
params...) ----> this === obj;
4. if as constructor: new func(params) ---> this === new created
object.

But if to describe a bit deeper, it also looks not so hard:

If call expression finds out a base object (which stands before the
property accessor - dot or brackets) of reference as an *object*, then
this object will be used as [this-value] (in points above, that point
2).

But here there's exceptions: if that object is *activation object*
(can be if we call internal function in other function) than used
[null-value] for that. Than if [this-value] determinate as [null-
value] (which makes not so much sense), then global object is used
instead (in points above that's point 1).
 
D

Dmitry A. Soshnikov

[...]
That's the key: without a caller, |this| has no intrinsic
meaning at all (which means that if all you can see is the inside of a
function, you cannot say what |this| refers to).
[...]

Regarding the "caller" concept there can be a little bit mess.
Earlier, I also thought that the |caller| - is the base object of
reference, but concerning the ECMA-262-3 that's wrong. Caller - is a
CallEpression, it *is always*. There can be no situation without
caller, as you mentioned, as a |caller| - is call expression. And
getting base object from the call expression - is already a
consequence, as by the spec:

--The *this* value depends on the *caller*-- (10.1.7)

-- The *caller provides the this value*. If the this value provided by
the caller is not an object (including
the case where it is null), then the this value is the global object.
-- (10.2.1)

So there's *always* caller, but not always base object is as needed.

In case of |null| it transforms to global object:

(function () { this; })();

Here:

(a) "(function () { this; })()" - caller (call expression);
(b) null - |this-value| determinate by the caller and transformed to
global.

In case when base object is an activation object (AO), again transform
from null to global takes place:

(function () {
function a() {
this;
}
a(); // the same as AO.a();
})();

where AO - is an activation object of the anonymous function context,
so here:

(a) "AO.a();" or simply "a()" - caller (call expression);
(b) AO - is a base object and in this case (by the spec, 10.1.6) it
transforms to null and after that - to global: AO -> null -> global.
 
D

Dmitry A. Soshnikov

On 30 Ñен, 22:03, "Richard Cornford" <[email protected]>
wrote:

[...]
That last should read "All three add non-Activation objects to scope
chains".
[...]

Yeah, thx for this additions, forgot that cases. Indeed, here will be
simple object which base will be used as |this-value|. As addition to
yours |with|-example:

try {
throw {
foo: function () {
alert(['This is not the Global oject too', this === window]);
}
};
} catch (ex) {
ex.foo();
}
 
D

Dmitry A. Soshnikov

On 30 Ñен, 22:03, "Richard Cornford" <[email protected]>
wrote:

[...]> That last should read "All three add non-Activation objects to scope

[...]

Yeah, thx for this additions, forgot that cases. Indeed, here will be
simple object which base will be used as |this-value|. As addition to
yours |with|-example:

try {
  throw {
    foo: function () {
      alert(['This is not the Global oject too', this === window]);
    }
  };

} catch (ex) {
  ex.foo();
}

Sorry, bad example, but with catch clause caller gets this as not the
object created by catch clause and put into the front of the scope
chain:

try {
throw function () {alert(this === window);}; // true
} catch (ex) {
ex();
}

But it should be:

ex(); === CatchClauseObject.ex(); => this - base of CatchClauseObject,
but here is global again.
 
D

Dmitry A. Soshnikov

That's the key: without a caller, |this| has no intrinsic
meaning at all (which means that if all you can see is the inside of a
function, you cannot say what |this| refers to).

Regarding the "caller" concept there can be a little bit mess.
Earlier, I also thought that the |caller| - is the base object of
reference, but concerning the ECMA-262-3 that's wrong. Caller - is a
CallEpression, it *is always*. There can be no situation without
caller, as you mentioned, as a |caller| - is call expression. And
getting base object from the call expression - is already a
consequence, as by the spec:
--The *this* value depends on the *caller*-- (10.1.7)
-- The *caller provides the this value*. If the this value provided by
the caller is not an object (including
the case where it is null), then the this value is the global object.
-- (10.2.1)
So there's *always* caller, but not always base object is as needed.

While that's true, it's not what I was trying to say. If a function is
never called, you cannot say what |this| in the function body would
refer to, just by looking at it.

Ah, yeah, got it.
I'd hoped to avoid technical terms like "activation object", going
instead for a simplified explanation, but I see now that this only leads
to more discussion.

Nope, that's a good idea to explain as easy as possible, I supports
you (as have written myself - "If to describe in very simplified
manner") but without missing ECMA-262-3 sense.
 
J

John G Harris

[...]
Still my fear of using 'this' remains. I ought to see a picture in front of
me about this, but I do not see yet.
[...]

There's nothing so hard to understand with [this-value]. First of all,
you should remember that [this-value] determinate and bind to context
*dynamicaly*.

If to describe in very simplified manner, you should remember only
four cases of call expression (that's the picture):

1. if as function: func(params) ----> this === global;
2. if as method: obj.func(params) ----> this === obj;
3. if apply/call used: func.apply(obj, [params]), func.call(obj,
params...) ----> this === obj;
4. if as constructor: new func(params) ---> this === new created
object.
<snip>

5. The function doesn't use 'this'.

Never forget the easy case.

John
 
T

Thomas 'PointedEars' Lahn

Dmitry said:
try {
throw function () {alert(this === window);}; // true
} catch (ex) {
ex();
}

Your test case is flawed as `window' is not a reference to the ECMAScript
Global Object. It is a reference to a host object that may exhibit (and
IIRC has exhibited before) peculiar, but specified behavior, especially with
comparison operators.

The sure way to retrieve a reference to the ECMAScript Global Object is to
assign `this' in the global execution context.


PointedEars
 
J

Jorge

Your test case is flawed as `window' is not a reference to the ECMAScript
Global Object.  (...)

In which browser is that so ?

ES-262, Edition 3, Final: 10.1.5 Global Object:
"Additional host defined properties. This may include a property whose
value is the global object itself; for example, in the HTML document
object model the window property of the global object is the global
object itself."

ES5-Final: 15.1 The Global Object:
"In addition to the properties defined in this specification the
global object may have additional host defined properties. This may
include a property whose value is the global object itself; for
example, in the HTML document object model the window property of the
global object is the global object itself."
 
D

Dmitry A. Soshnikov

Your test case is flawed as `window' is not a reference to the ECMAScript
Global Object. šIt is a reference to a host object that may exhibit (and
IIRC has exhibited before) peculiar, but specified behavior, especially with
comparison operators.
[...]

Yeah, I know about == and === in IE for |self|, |window| and |this|.
But actually, it doesn't matter that window - is the host object, and |
this| in global context - is the global object itself (and native
object). More that, window - is the recursive reference to the global
object:

<pseudo-code:>

global = {
window: global
};

<evaluation of global context:>
this = global;

But example above is not about that stuff. It was about special
objects mentioned by Richard which are should/could be used as the
base objects in determination the |this|-value on entering execution
context.

And in case of |with|-statement, that's truly evaluates to the object
added by |with| to the scope chain. But in case of |catch|-clause
which is also added (like as an object provided by |with|) in front of
scope chain, that's not so.

[...]
The sure way to retrieve a reference to the ECMAScript Global Object is to
assign `this' in the global execution context.
[...]

I know, but we don't need any assignments and this all stuff with |
native global| and |host window| objects as, repeat, we're talking
about different thing. Just use |alert(this);| then.

try {
throw function () {
alert(this);
};
} catch (ex) {
ex();
}

|catch|-clause is evaluated as follow:

__catchObject = {
ex: function () {
alert(this);
};
};

Scope = __catchObject + AO/VO + [[Scope]]

So, the caller |ex()| or even better to say |__catchObject.ex()| above
should (as in |with|-statement) provide |this|-value as |
__catchObject|, but it provides it (at the end point of
transformations) to global object. I don't see in spec that "in case
where base object is the catch-clause object, use |null| (and after
that the global object)". But this correctly said about activation
object which should provide |null| (and after that the global object)
as |this|-value.
 
L

Lasse Reichstein Nielsen

Jorge said:
In which browser is that so ?

It seems IE is the main culprit.
var glob = (function(){return this;})();
var win = glob.window;
alert(glob === win); // Alerts "false" in IE8.
Other browsers might have similar quirks, but not necessarily as easily
detectable.
ES-262, Edition 3, Final: 10.1.5 Global Object:
"Additional host defined properties. This may include a property whose
value is the global object itself; for example, in the HTML document
object model the window property of the global object is the global
object itself."

This was written at a time when the "window" property hadn't even been
attempted formalized in a W3C specification, so this text can hardly
be normative.
ES5-Final: 15.1 The Global Object:
"In addition to the properties defined in this specification the
global object may have additional host defined properties. This may
include a property whose value is the global object itself; for
example, in the HTML document object model the window property of the
global object is the global object itself."

Seems like a cut-and-paste of the above, and by the time the HTML 5
specification is finished, it will even be wrong.

The HTML 5 specification specifies behavior that is closer to IE's.

In HTML 5 (which, unlike earlier HTML versions, specifies both the
syntax and the ECMAScript DOM bindings for the language), a Window
object is not exposed directly. Instead it's exposed through a
WindowProxy object that proxies the Window object itself, but is not
equal to it. This allows scripts to hold on to the proxy while the
actual window object changes below it (e.g., by navigating away from a
page while having a setTimeout function pending).



So IE uses the Window object as global object for the JScript code,
but the "window" property returns a WindowProxy object, which behaves
identically, but is not equal (at least not by ===) to each other.
This almost matches HTML 5 behavior, except that in HTML 5, the "this"
operator should evaluate to the WindowProxy object of the current
global object/Window, not the Window itself.


It seem the HTML 5 specification group specifying behavior of "this"
that is contrary to the ECMAScript specification of it. It would match
better if HTML 5 said that the WindowProxy object *was* the global
object, instead of saying that Window object is the global object, but
"this" evaluates to the WindowProxy object.

/L
 
T

Thomas 'PointedEars' Lahn

Lasse said:
It seems IE is the main culprit.
var glob = (function(){return this;})();
var win = glob.window;
alert(glob === win); // Alerts "false" in IE8.

Other browsers might have similar quirks, but not necessarily as easily
detectable.

But you of all people should know that this is not a proof of what I was
saying either. said:
This was written at a time when the "window" property hadn't even been
attempted formalized in a W3C specification, so this text can hardly
be normative.

The second part is not normative because it is an *example* to begin with.


PointedEars
 
G

Garrett Smith

Lasse said:
It seems IE is the main culprit.
var glob = (function(){return this;})();
var win = glob.window;
alert(glob === win); // Alerts "false" in IE8.
Other browsers might have similar quirks, but not necessarily as easily
detectable.


This was written at a time when the "window" property hadn't even been
attempted formalized in a W3C specification, so this text can hardly
be normative.


Seems like a cut-and-paste of the above, and by the time the HTML 5
specification is finished, it will even be wrong.

Similar with Function.prototype.toString, which is not what
implementations do.
The HTML 5 specification specifies behavior that is closer to IE's.

[explanation]

http://www.w3.org/TR/html5/browsers.html#the-windowproxy-object


So IE uses the Window object as global object for the JScript code,
but the "window" property returns a WindowProxy object, which behaves
identically, but is not equal (at least not by ===) to each other.
This almost matches HTML 5 behavior, except that in HTML 5, the "this"
operator should evaluate to the WindowProxy object of the current
global object/Window, not the Window itself.

The this /operator/?
It seem the HTML 5 specification group specifying behavior of "this"
that is contrary to the ECMAScript specification of it. It would match
better if HTML 5 said that the WindowProxy object *was* the global
object, instead of saying that Window object is the global object, but
"this" evaluates to the WindowProxy object.

Sure. There are cases where there is no "this" value. For example, in an
assignment expression.

Simple assignment results in adding a property to the global
object, as per ECMA-262 r3, 8.7.2, PutValue.

For example, in a document that has not finished loading, assigning
onload results in window onload firing.

<!doctype html>
<html>
<head>
<title>test global onload</title>
<script type="text/javascript">
onload = function(){
result = "pass";
};
setTimeout(done, 500);
function done(){
document.body.innerHTML = result;
}
</script>
</head>
<body></body>
</html>

Result: "pass"

The function was called (in the windows load event), setting |result| to
"pass". An onload property was assigned to the global object, which is a
WindowProxy.

I've noticed that "self.onload" fails in IE6. Changing the above example
from |this.onload| to |self.onload| result is "fail" in IE6.
 

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
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top