this confusion

S

Stevo

Simplified example code which can be copy/pasted and will exhibit the
problem.

var ob={id:2};
ob.alertid=function(){alert("id="+this.id);}
ob.funcs=[ob.alertid];
ob.testalert=function(){
this.alertid(); //this works
this.funcs[0](); //this doesn't
}

ob.testalert();

I have an object with an id property. The alertid function alerts that
id property if it's called directly, but not if it's called via an array
of function pointers. I don't understand the difference. Why is 'this'
different in those two cases. It's the same object method isn't it.

The output is:

id=2
id=undefined
 
R

RobG

Simplified example code which can be copy/pasted and will exhibit the
problem.

var ob={id:2};
ob.alertid=function(){alert("id="+this.id);}
ob.funcs=[ob.alertid];
ob.testalert=function(){
this.alertid(); //this works
this.funcs[0](); //this doesn't

}

ob.testalert();

I have an object with an id property. The alertid function alerts that
id property if it's called directly, but not if it's called via an array
of function pointers. I don't understand the difference. Why is 'this'
different in those two cases. It's the same object method isn't it.

I think the best post I've seen about the this keyword is the one here
by Mike Winter:

<URL:
http://groups.google.com.au/group/c...yword"+operator&rnum=5&hl=en#ec26cd885e01c292

The first part is about closures, the second part on this is
excellent.
 
T

Thomas 'PointedEars' Lahn

Stevo said:
[...]
var ob={id:2};
ob.alertid=function(){alert("id="+this.id);}
ob.funcs=[ob.alertid];
ob.testalert=function(){
this.alertid(); //this works
this.funcs[0](); //this doesn't
}

ob.testalert();

I have an object with an id property. The alertid function alerts that
id property if it's called directly, but not if it's called via an array
of function pointers. I don't understand the difference. Why is 'this'
different in those two cases. It's the same object method isn't it.

It is the same Function object. But it is called differently.
The output is:

id=2
id=undefined

With the second call you are calling the method as the property of the Array
object, not of the owner of the property (`funcs') the reference to it is
assigned to (`ob'). Try this ;-)

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

var id = 2;

var ob = {
id: 42,

alertid: function()
{
window.alert([
"this.id = " + this.id,
"this = " + this,
"typeof this = " + typeof this,
"this.constructor = " + this.constructor
].join(",\n"));
}
};

ob.funcs = [ob.alertid];

ob.testalert = function()
{
this.alertid(); // this.constructor == Object
this.funcs[0](); // this.constructor == Array
};

ob.testalert();


HTH

PointedEars
 
D

David Mark

Simplified example code which can be copy/pasted and will exhibit the
problem.

var ob={id:2};
ob.alertid=function(){alert("id="+this.id);}
ob.funcs=[ob.alertid];
ob.testalert=function(){
this.alertid(); //this works

Right. Because you called a method of the ob object. In this case,
"this" is ob, which has an id property.
this.funcs[0](); //this doesn't

funcs[0] holds a reference to an anonymous function. The fact that ob
has a property (alertid method) that references it as well is
meaningless. In this case, "this" refers to the anonymous function,
which has no id property.
 
S

Stevo

David said:
In this case, "this" refers to the anonymous function,
which has no id property.

Thanks David, Randy, Thomas and Rob. You all said the same thing
basically, this differs depending on how it's called. Excellent link
Rob, that's one to bookmark.

I've altered the alertid function to add 'that' and it now works.

var ob={id:2};
ob.alertid=function(){var that=ob;alert("id="+that.id);}
ob.funcs=[ob.alertid];
ob.testalert=function(){
this.alertid();
this.funcs[0]();
}
ob.testalert();

That has the name ob hard-coded in the alertid function though. I wonder
if it's possible to create 'that' without knowing the name of the
object? Take the following example with ??? where I don't know what to set:

var ob_a={id:"a"};
var ob_b={id:"b"};
var alertid=function(){var that=???;alert("id="+that.id);}
ob_a.alertid=alertid;
ob_b.alertid=alertid;

I'm guessing that there's no way to define 'that' which would work for
both objects there, and I'd have to define an anonymous function for
each object, with hard-coded references to ob_a and ob_b in them like so:

var ob_a={id:"a"};
var ob_b={id:"b"};
ob_a.alertid=function(){var that=ob_a;alert("id="+that.id);};
ob_b.alertid=function(){var that=ob_b;alert("id="+that.id);}
 
T

Thomas 'PointedEars' Lahn

Stevo said:
[...]
var ob={id:2};
ob.alertid=function(){var that=ob;alert("id="+that.id);}
ob.funcs=[ob.alertid];
ob.testalert=function(){
this.alertid();
this.funcs[0]();
}
ob.testalert();

That has the name ob hard-coded in the alertid function though. I wonder
if it's possible to create 'that' without knowing the name of the
object?

No, it can't be (other than parsing the source code somehow). Objects have
no name, they have identity (two compared object "instances"[1] are either
the same object or they are different objects). `ob' is but the identifier
of only one possible reference of that object (in fact, the name of a
property of the Variable Object, the Global Object here). And since a
property can be also an object reference (as you have observed now with the
Array object), you cannot tell the owner(s) of a property (apart) by looking
at the property value. At least not in current ECMAScript implementations.


PointedEars
___________
[1] This has nothing to do with instantiation or classes. I just can't
think of a better term for this theoretical language construct.
 
T

Thomas 'PointedEars' Lahn

Stevo said:
[...] I wonder if it's possible to create 'that' without knowing the name of the
object? Take the following example with ??? where I don't know what to set:

var ob_a={id:"a"};
var ob_b={id:"b"};
var alertid=function(){var that=???;alert("id="+that.id);}
ob_a.alertid=alertid;
ob_b.alertid=alertid;

I'm guessing that there's no way to define 'that' which would work for
both objects there, and I'd have to define an anonymous function for
each object, with hard-coded references to ob_a and ob_b in them like so:

var ob_a={id:"a"};
var ob_b={id:"b"};
ob_a.alertid=function(){var that=ob_a;alert("id="+that.id);};
ob_b.alertid=function(){var that=ob_b;alert("id="+that.id);}

var alertid = function(that){ alert("id=" + that.id); };
// ...
ob_a.alertid = function() { alertid(this); };
ob_b.alertid = function() { alertid(this); };

or

var alertid = function(){ alert("id=" + this.id); }
// ...

and then either

ob_a.alertid = function() { alertid.call(this); };
ob_b.alertid = function() { alertid.call(this); };

or

ob_a.alertid = function() { alertid.apply(this); };
ob_b.alertid = function() { alertid.apply(this); };


HTH

PointedEars
 
S

Stevo

Thomas said:
No, it can't be (other than parsing the source code somehow). Objects have
no name, they have identity (two compared object "instances"[1] are either
the same object or they are different objects). `ob' is but the identifier
of only one possible reference of that object


I've figured out a way that's satisfactory even if not perfect:-

var ob_a={id:"a",funcs:[]};
ob_a.alertid=function(){alert("id="+this.id);}
ob_a.funcs[0]=ob_a.alertid;
ob_a.funcs.id=ob_a.id; // ### -- this is the key line -- ###
ob_a.alertid(); //works! this.id is actually ob_a.id
ob_a.funcs[0](); //works! this.id is actually ob_a.funcs.id

I copy the id property of the ob_a object into the funcs array object.
Doing that gives the funcs array the same value. I know it's not a
reference to this.id, instead it's a copy of it. That's sufficient though.

Having that id copy also enables me to create a dynamic that property in
the alertid function like this (if I want to). In this case all the
objects start with ob_ followed by what's in the id string. If that
wasn't the case, then I could just write the name of the variable as a
new property of the funcs array also :-

ob_a.alertid=function(){
var that=window["ob_"+this.id];
alert("id="+that.id); //this will now use ob_a.id
}

Thanks for the knowledge growth guys.
 
R

ron.h.hall

I think the best post I've seen about the this keyword is the one here
by Mike Winter:

<URL:http://groups.google.com.au/group/comp.lang.javascript/browse_frm/thr...

The first part is about closures, the second part on this is
excellent.

With regard to the second part only, and in spite of many excellent
posts that Mike contributed, this one doesn't quite make that rating
in my book.

The first problem is the use of the term "this operator" which, quite
remarkably, also seems to have found its way into Mozilla JS 1.5
documentation:

<URL:http://developer.mozilla.org/en/docs/
Core_JavaScript_1.5_Reference:Operators:Special_Operators:this_Operator>

"this" in Javascript is not an operator, it is a (read-only) variable
and can be used as any other variable operand of type
"object" (although, as it is read-only, it cannot be directly assigned
within the program).

"this" can implicitly given a value, with the most direct implicit
assignment being attained through the function.prototype.call/apply
methods. Nonetheless, in the most common usage, "this" takes it value
initially as a reference to the global object, and automatically
changes as execution contexts are created (and restored) for method
calls in accordance with the way in which the reference to the method
was designated.

If the reference to the method is obtained without use of dot or
bracket notation, "this" is assigned a reference to the global object.
On the other hand if dot or bracket notation is used to arrive at the
reference, "this" is assigned the object at the end of the accessor
path that leads to the reference.

In other words, a function invoked as f(...) will have a "this" value
of the global object, whereas a.b.c.f(...) would have a "this" value
of c.

Perhaps most non-intuitive in the above is that the above paragraph
applies even when an inner function is called, where one might expect
the "this" value to be preserved (as it is when code under the eval
function is invoked).

So the second problem with Mike's post is that it over-complicates the
description of what one should expect of the "this" value to be by
involving the variable object, scope chain and the "new" operator[1]
in the description.

See "Objects and this" at

<URL:http://javascript.crockford.com/survey.html>

for a much more succinct, easy to grasp, description.

[1] The new operator relationship to "this" is really just a special
case of function.prototype.call (performed internally) of the
constructor function.
 
H

Henry

On Aug 16, 3:50 pm, (e-mail address removed) wrote:
In other words, a function invoked as f(...) will have a
"this" value of the global object,

function f(){
var x = (this+'');
}

with(
{
f:f,
toString:function(){alert('I am not the global object');}
}
){
f(); // alerts: I am not the global object
// So the - this - value when - f() - is
// executed is _not_ the global object.
}

You appear to have failed to take into account the role of variable
objects and the scope chain in determining the - this - value.

So the second problem with Mike's post is that it over-complicates
the description of what one should expect of the "this" value to
be by involving the variable object, scope chain and the "new"
operator[1] in the description.
<snip>
 
T

Thomas 'PointedEars' Lahn

The first problem is the use of the term "this operator" which, quite
remarkably, also seems to have found its way into Mozilla JS 1.5
documentation:

<URL:http://developer.mozilla.org/en/docs/
Core_JavaScript_1.5_Reference:Operators:Special_Operators:this_Operator>

"this" in Javascript is not an operator, it is a (read-only) variable

It is neither. `this' is not defined as a property of a Variable Object of
an execution context. `this' is a reserved word, a keyword, and it can be
considered "a value" ([ES3], 10.2).
[...]
If the reference to the method is obtained without use of dot or
bracket notation, "this" is assigned a reference to the global object.

That is over-simplifying the matter. `this' within a method refers to the
calling object ([ES3], 10.2.3). Not using an ObjectReference is having
identifier resolution to try the next object in the scope chain, which is
often, but not always, the Global Object ([ES3], 10.1.4). At least the
MSHTML DOM proves that there is another object in the scope chain before
the Global Object.
On the other hand if dot or bracket notation is used to arrive at the
reference, "this" is assigned the object at the end of the accessor
path that leads to the reference.

That is over-complicating the matter. `this' within a method refers to the
calling object (see above).
In other words, a function invoked as f(...) will have a "this" value
of the global object, whereas a.b.c.f(...) would have a "this" value
of c.

Globally declared functions are methods of the Global Object, as that is the
Variable Object of the global execution context ([ES3], 13). So the value
of the `this' value in that context is a reference to the Global Object.

Methods are function-type properties ([ES3], 4.3.3).
[...]
So the second problem with Mike's post is that it over-complicates the
description of what one should expect of the "this" value to be by
involving the variable object, scope chain and the "new" operator[1]
in the description.

So far for over-complicating. Please read [ES3] before you post even more
of such half-truths.

[ES3]
http://developer.mozilla.org/en/docs/JavaScript_Language_Resources#JavaScript_1.x


PointedEars
 
R

ron.h.hall

On Aug 16, 3:50 pm, (e-mail address removed) wrote:


function f(){
var x = (this+'');

}

with(
{
f:f,
toString:function(){alert('I am not the global object');}
}
){
f(); // alerts: I am not the global object
// So the - this - value when - f() - is
// executed is _not_ the global object.

}

You appear to have failed to take into account the role of variable
objects and the scope chain in determining the - this - value.

So, given the Michael Winter post under discussion, what would you say
the "The global and activation/variable objects:" section, that brings
under consideration scope chains, activation and variable objects,
leads to as the "this" value in your example?

"with", as always, is a special case (and that is part of the reason
that its use is generally recommended against). The relevance of the
scope chain in this case has to do with search order, and is
incidental to the setting of the "this" value on call to a method
found as a property of the "with" computed object.

Syntactically, you are correct, that explicit accessor processing does
not occur at the time of the call. Nonetheless, logically, the
property when found can be thought of as

withComputedObject[propertyName]

, and therefore the simple rule given for determination of the "this"
value under a call applies.
 
R

RobG

With regard to the second part only, and in spite of many excellent
posts that Mike contributed, this one doesn't quite make that rating
in my book.

The first problem is the use of the term "this operator" which,

Mike explained in another post why he uses that term. I've spent some
time trying to find it but can't.

[...]
If the reference to the method is obtained without use of dot or
bracket notation, "this" is assigned a reference to the global object.
On the other hand if dot or bracket notation is used to arrive at the
reference, "this" is assigned the object at the end of the accessor
path that leads to the reference.

In other words, a function invoked as f(...) will have a "this" value
of the global object, whereas a.b.c.f(...) would have a "this" value
of c.

Perhaps most non-intuitive in the above is that the above paragraph
applies even when an inner function is called, where one might expect
the "this" value to be preserved (as it is when code under the eval
function is invoked).

So the second problem with Mike's post is that it over-complicates the
description of what one should expect of the "this" value to be by
involving the variable object, scope chain and the "new" operator[1]
in the description.

I think he's being thorough. His explanation regarding identifier
resolution explains how the this keyword of an inner function is a
reference to the global object, even if the this keyword of the outer
function is some other value.

e.g.

function foo(){
alert('foo: this == window : ' + !!(this == window));
function bar() {
alert('bar: this == window : ' + !!(this == window));
}
bar();
}
var x = {};
x.foo = foo;
x.foo(); // foo: this == window : false
// bar: this == window : true


When resolving the local variable bar, it is found on foo's variable
object and so its this keyword is set to the global object, even
though the outer function, foo, has its this keyword set to x.

If a programmer wants the inner function to have access to the outer
function's this keyword, they can do:

function foo(){
var fooThis = this;
function bar() {
// Use fooThis
}
bar();
}

or

function foo(){
function bar() {
// this = foo's this;
}
bar.call(this);
}

See "Objects and this" at

<URL:http://javascript.crockford.com/survey.html>

for a much more succinct, easy to grasp, description.

It is a simple description that covers the majority of cases, but it
doesn't explain why. One reason I like Mike's explanations is that
they can be read and understood in conjunction with the ECMAScript
specification [1]. I don't think Douglas Crockford's can (which isn't
a criticism, I suspect that was never his intention).


1. Richard Cornford's posts fall into the same category, though they
are often much more difficult to understand.
 
R

ron.h.hall

On Aug 17, 12:50 am, (e-mail address removed) wrote:
The first problem is the use of the term "this operator" which,

Mike explained in another post why he uses that term. I've spent some
time trying to find it but can't.

[...]
It would be interesting to see that. The terminology used is contrary
to any standard definition of "operator" versus "variable", where, in
general terms, an operator invokes an action that creates a result,
and a variable provides storage for a result.

ECMAScript 262/3 does not list "this" as an operator (not to my
surprise, nor does it list it as a variable, because for the
specification it's not. Perhaps pseudo-variable would a better term).
So the second problem with Mike's post is that it over-complicates the
description of what one should expect of the "this" value to be by
involving the variable object, scope chain and the "new" operator[1]
in the description.

I think he's being thorough. His explanation regarding identifier
resolution explains how the this keyword of an inner function is a
reference to the global object, even if the this keyword of the outer
function is some other value.

And, as always, he deserves commendation for his thoroughness.
However, in many cases you need to know what more than why, especially
when the why is relatively complex.
e.g.

function foo(){
alert('foo: this == window : ' + !!(this == window));
function bar() {
alert('bar: this == window : ' + !!(this == window));
}
bar();}

var x = {};
x.foo = foo;
x.foo(); // foo: this == window : false
// bar: this == window : true
Or, to preserve "this", the bar() can be changed to bar.call(this) -
just a touch more convoluted than one might expect.
When resolving the local variable bar, it is found on foo's variable
object and so its this keyword is set to the global object, even
though the outer function, foo, has its this keyword set to x.

But why should I care when the rationale is nothing more than that's
what the specification says it will be, as long as I have a way of
knowing what it will be, or a way of setting it to what I want it to
be?
If a programmer wants the inner function to have access to the outer
function's this keyword, they can do:

function foo(){
var fooThis = this;
function bar() {
// Use fooThis
}
bar();

}

or

function foo(){
function bar() {
// this = foo's this;
}
bar.call(this);

}
See "Objects and this" at

for a much more succinct, easy to grasp, description.

It is a simple description that covers the majority of cases, but it
doesn't explain why. One reason I like Mike's explanations is that
they can be read and understood in conjunction with the ECMAScript
specification [1]. I don't think Douglas Crockford's can (which isn't
a criticism, I suspect that was never his intention).
And that's to some extent a question of whether everyone who wishes to
program in JavaScript should have to read and be able to comprehend
the ECMAScript specification in order to be able to use the language
effectively.

Given the amount of confusion over "this", even by those who have a
fair degree of experience with the language, I prefer to see
something presented in abstract form that can be readily grasped
without the involvement of relatively complex internal specification,
at least where possible.

Even so, as the "this" value setting seems to violate the "Principle
of Least Astonishment" in some cases, a simple rule is as good as an
explanation from the specification, as there may be no more rationale
found there than in a rule.

<...>
 
H

Henry

So, given the Michael Winter post under discussion, what would you
say the "The global and activation/variable objects:" section, that
brings under consideration scope chains, activation and variable
objects, leads to as the "this" value in your example?

The circumstances under which the - this - keyword will not be a
reference to the global object only occur if when what may be referred
to as the operand of the 'call operator' (or 'the bit before the
opening parenthesis of the arguments list', if you prefer) evaluates
as an instance of the internal Reference type. The two things that may
evaluate as instances of the internal Reference type are property
accessors and Identifiers, and the - f - in - f(); - is an Identifier
and so will (must) evaluate to a Reference type. So the question is
not why in this example the - this - keyword refers to something that
is not the global object but rather why it dose not refer to something
other than the global object with almost all other uses in the form of
- identifier() -. The answer to that is precisely what Michel Winter
is addressing when talking about activation/variable objects.
"with", as always, is a special case

Not really. The - with - statement does something very simple; places
an object on the scope chain, but doing that has implications for the
outcome of - this - assignments by the general mechanism whenever
Identifiers are the operand of the 'call operator'
(and that is part of the reason
that its use is generally recommended against).
The relevance of the
scope chain in this case has to do with search order, and is
incidental to the setting of the "this" value on call to a method
found as a property of the "with" computed object.

The search order is the coincidental factor, it is only the fact that
the object added to the scope chain is not an Activation/Variable
object (unlike every other object on the scope chain at the time) that
allows the - this - reference to be something other than the global
object.
Syntactically, you are correct,

Logically I am correct as well. The statement: "a function invoked as
f(...) will have a "this" value of the global object" is proved false
by any single empirical demonstration that contradicts it.
that explicit accessor processing does
not occur at the time of the call. Nonetheless, logically, the
property when found can be thought of as

withComputedObject[propertyName]

It "can be thought of as ..." if you also regard normal (without -
with - statements) Identifier resolution as the equivalent of:-

varibleObject[propertyName]

- and if you do that you need to explain why - variableOjbect - is not
the - this - value.
, and therefore the simple rule given for determination of the
"this" value under a call applies.

Well, no. Your "simple rule" is too simple. And it does not even
address cases such as:-

var test = 'global';

function AnObject(){
this.test = 'AnOjbect';
};
AnObject.prototype.method1 = function(){
return this.method2;
};
AnObject.prototype.method2 = function(){
alert(this.test);
};

var obj = new AnObject();

obj.method1()(); //which alerts 'global'.
 
R

ron.h.hall

On Aug 17, 2:44 am, (e-mail address removed) wrote:



The circumstances under which the - this - keyword will not be a
reference to the global object only occur if when what may be referred
to as the operand of the 'call operator' (or 'the bit before the
opening parenthesis of the arguments list', if you prefer) evaluates
as an instance of the internal Reference type. The two things that may
evaluate as instances of the internal Reference type are property
accessors and Identifiers, and the - f - in - f(); - is an Identifier
and so will (must) evaluate to a Reference type. So the question is
not why in this example the - this - keyword refers to something that
is not the global object but rather why it dose not refer to something
other than the global object with almost all other uses in the form of
- identifier() -. The answer to that is precisely what Michel Winter
is addressing when talking about activation/variable objects.
What Michael Winter was addressing is not a matter of disagreement.
You didn't answer the question.
Not really. The - with - statement does something very simple; places
an object on the scope chain, but doing that has implications for the
outcome of - this - assignments by the general mechanism whenever
Identifiers are the operand of the 'call operator'


The search order is the coincidental factor, it is only the fact that
the object added to the scope chain is not an Activation/Variable
object (unlike every other object on the scope chain at the time) that
allows the - this - reference to be something other than the global
object.

It doesn't really matter where it's located. The differentiator is
that the "with" computed object is a program accessible object,
whereas others you mention above are not (and are not intended to be,
and that's why the specification doesn't allow them to find their way
into the "this" value).
Syntactically, you are correct,

Logically I am correct as well. The statement: "a function invoked as
f(...) will have a "this" value of the global object" is proved false
by any single empirical demonstration that contradicts it.
that explicit accessor processing does
not occur at the time of the call. Nonetheless, logically, the
property when found can be thought of as
withComputedObject[propertyName]

It "can be thought of as ..." if you also regard normal (without -
with - statements) Identifier resolution as the equivalent of:-

varibleObject[propertyName]

- and if you do that you need to explain why - variableOjbect - is not
the - this - value.
I don't see the necessity of going there, but wouldn't that in general
just be:

internalObject[propertyName] => this à globalObject under call

Well, no. Your "simple rule" is too simple. And it does not even
address cases such as:-

var test = 'global';

function AnObject(){
this.test = 'AnOjbect';};

AnObject.prototype.method1 = function(){
return this.method2;};

AnObject.prototype.method2 = function(){
alert(this.test);

};

var obj = new AnObject();

obj.method1()(); //which alerts 'global'.

Quite right.

Does the Michael Winter (non-too-simple) description, of which you
seem to be a defender, "even address cases such as:" the above? If
so, where?
 

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,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top