XmlHttpRequest.onreadystatechange <-> this-keyword

N

news

Hi. I hope someone can help me with this ^^

I'm having some trouble understanding how I can define my own function
to be run (not in-line) when an AJAX call is done without having to
keep a. Have I understood correctly that
XmlHttpRequest.onreadystatechange is a function within the
XmlHttpRequest class that one "overrides" when using ajax? If so, why
does not the this-keyword work within this function? (Like when
defining your own classes). I thought maybe the garbage collection
messed it up, but I tried defining the varable in global scope and I
still got the same result. I'll try to illustrate what I'm trying to
do below.

function processResponse() {
if(this.readyState == 4) { //this.readyState is undefined!
//...
}
}

function getRequest() {
//...
}

function sendRequest(responseFunction, parameters) {
var request = getRequest();
request.onreadystatechange = responseFunction;
request.open("POST", "url", true);
request.setRequestHeader('Content-Type', 'application/x-www-form-
urlencoded');
request.send(parameters);
}

sendRequest(processResponse, "");


---

When defining a class it works wonderfully:

function MyClass() {
this.x = 5;
this.getX = myClassGetX;
}

function myClassGetX() {
return this.x;
}
 
N

news

Hi. I hope someone can help me with this ^^

I'm having some trouble understanding how I can define my own function
to be run (not in-line) when an AJAX call is done without having to
keep a.

* ...without having to keep a reference to the request.
Have I understood correctly that
XmlHttpRequest.onreadystatechange is a function within the
XmlHttpRequest class that one "overrides" when using ajax? If so, why
does not the this-keyword work within this function? (Like when
defining your own classes). I thought maybe the garbage collection
messed it up, but I tried defining the varable in global scope and I

* ...defining the request-varable in global scope...
 
N

news

Hi. I hope someone can help me with this ^^

I'm having some trouble understanding how I can define my own function
to be run (not in-line) when an AJAX call is done without having to
keep a. Have I understood correctly that

Clarification: "...without having to keep a reference to the request
object."
XmlHttpRequest.onreadystatechange is a function within the
XmlHttpRequest class that one "overrides" when using ajax? If so, why
does not the this-keyword work within this function? (Like when
defining your own classes). I thought maybe the garbage collection
messed it up, but I tried defining the varable in global scope and I

Clarification: "...defining the request-varable in global scope..."
 
T

Tom Cole

Clarification: "...without having to keep a reference to the request
object."


Clarification: "...defining the request-varable in global scope..."






- Show quoted text -

I can't help with the why part (I just don't have the level of
understanding of the underlying mechanics like some of the folks in
this group do), but I can help with the how (to fix it) part...

First change your sendRequest to:

function sendRequest(responseFunction, parameters) {
var request = getRequest();
request.onreadystatechange = new function()
{ responseFunction(request); }
request.open("POST", "url", true);
request.setRequestHeader('Content-Type', 'application/x-www-form-
urlencoded');
request.send(parameters);
}

This will now pass your XMLHttpRequest object to your callback
handler. Note that you DO NOT need to change your call to sendRequest,
you can leave it as it is:

sendRequest(processResponse, "");

What you need to do next is define an input parameter for your
callback handler to assign the XMLHttpRequest to:

function processResponse(request) {
if(request.readyState == 4) {
// Do Stuff...
}
}

HTH, at least with the how part. Maybe someone else can chime in on
why.
 
H

Henry

* ...without having to keep a reference to the request.

There has to be a reference to the object somewhere, and it has to be
somewhere you can get at it if you are going to use it.

No, it is a property of the object. The value of that property may be
a function, if you assign one to it.

There are no classes in javascript.

No, it is a property of an object that you either assign a value to or
you don't.

It does work within that function, it just does not refer to the thing
you are expecting it to. In javascript the - this - value is decided
at runtime by the way in which you call a function. In the code you
write this gives you total control over what a - this - value will be
for any call to a function. However, XML HTTP request objects are host
objects that execute native code to achieve what they do and when
_they_ call any functions that may have been assigned to their -
onreadystatechange - properties they may or may not do so in a way
that results in the - this - value within the function referring to
the XML HTTP request object. And in practice some do and some do not,
and you have seen one that does not.

There are no classes in javascript, and emulating class-like behaviour
in javascript still does not create any associations between functions
and object instances (in the normal cause of things). What you think
of as 'classes' in your code work because you call the methods of the
'class' instances in a way that results in the - this - value within
those functions being assigned a reference to the object instance.

Garbage collection is unrelated to the nature of the - this - value.
but I tried defining the varable in global scope and I

* ...defining the request-varable in global scope...

Don't ever do that, because requests should be asynchronous and a
single global variable could not cope with more than one request
happening at the same time (or overlapping).

The usual approach is to use closures and temporarily store an
isolated reference to the XML HTTP request object in a closure. See:-


That is not very efficient:-

function MyObject() {
this.x = 5;
}
MyObject.prototype.getX = function() {
return this.x;
};
 
H

Henry

On Apr 1, 1:44 pm, Tom Cole wrote:
First change your sendRequest to:

function sendRequest(responseFunction, parameters) {
var request = getRequest();
request.onreadystatechange = new function()
<snip>
^^^
It is not going to work very well with that - new - operator in there.
 
N

news

*snip*
I can't help with the why part (I just don't have the level of
understanding of the underlying mechanics like some of the folks in
this group do), but I can help with the how (to fix it) part...

First change your sendRequest to:

function sendRequest(responseFunction, parameters) {
var request = getRequest();
request.onreadystatechange = new function()
{ responseFunction(request); }
request.open("POST", "url", true);
request.setRequestHeader('Content-Type', 'application/x-www-form-
urlencoded');
request.send(parameters);

}

This will now pass your XMLHttpRequest object to your callback
handler. Note that you DO NOT need to change your call to sendRequest,
you can leave it as it is:

sendRequest(processResponse, "");

What you need to do next is define an input parameter for your
callback handler to assign the XMLHttpRequest to:

function processResponse(request) {
if(request.readyState == 4) {
// Do Stuff...
}

}

HTH, at least with the how part. Maybe someone else can chime in on
why.

Thanks! Actually I had a temporary solution here that was pretty close
to that =)
 
N

news

*snip*
No, it is a property of the object. The value of that property may be
a function, if you assign one to it.

I see.
There are no classes in javascript.

I have trouble seeing that :)
No, it is a property of an object that you either assign a value to or
you don't.


It does work within that function, it just does not refer to the thing
you are expecting it to. In javascript the - this - value is decided
at runtime by the way in which you call a function. In the code you
write this gives you total control over what a - this - value will be
for any call to a function. However, XML HTTP request objects are host
objects that execute native code to achieve what they do and when
_they_ call any functions that may have been assigned to their -
onreadystatechange - properties they may or may not do so in a way
that results in the - this - value within the function referring to
the XML HTTP request object. And in practice some do and some do not,
and you have seen one that does not.

I found that a bit hard to understand. The way a function is called?
There are no classes in javascript, and emulating class-like behaviour
in javascript still does not create any associations between functions
and object instances (in the normal cause of things). What you think
of as 'classes' in your code work because you call the methods of the
'class' instances in a way that results in the - this - value within
those functions being assigned a reference to the object instance.


Garbage collection is unrelated to the nature of the - this - value.

I was thinking of that the reference to the object was defined in the
sendRequest-scope.
Don't ever do that, because requests should be asynchronous and a
single global variable could not cope with more than one request
happening at the same time (or overlapping).

That was merely for testing - to keep the object away from the garbage-
collector. I guess the object lives on somehow anyway?

*snip*
That is not very efficient:-

function MyObject() {
this.x = 5;}

MyObject.prototype.getX = function() {
return this.x;

};

This one's new to me. However I have taken a little peek at the
prototype-keyword in the context of inheritence. Thanks for the tip.
 
J

Joost Diepenmaat

I found that a bit hard to understand. The way a function is called?

How about this (heh):

function rthis() {
return this;
}

rthis(); // returns the global object.

var obj = { meth: rthis }; // obj.meth === rthis

obj.meth(); // returns obj

new rthis(); // returns a new object with rthis.prototype as it's
// prototype

So, "this" is always dependent on how the function in question is
called, and nothing else.
That was merely for testing - to keep the object away from the garbage-
collector. I guess the object lives on somehow anyway?

As long as there is a reachable reference, yes.
 
E

Evertjan.

Joost Diepenmaat wrote on 01 apr 2008 in comp.lang.javascript:
function rthis() {
return this;
}

rthis(); // returns the global object.
So, "this" is always dependent on how the function in question is
called, and nothing else.

So if the function was called rthat() and not rthis() ..... ?

Grapje!
 
J

Joost Diepenmaat

Evertjan. said:
Joost Diepenmaat wrote on 01 apr 2008 in comp.lang.javascript:


So if the function was called rthat() and not rthis() ..... ?

No that's what the NAME is called. :)

`The name of the song is called "HADDOCKS' EYES."'

`Oh, that's the name of the song, is it?' Alice said, trying to feel
interested.

`No, you don't understand,' the Knight said, looking a little
vexed. `That's what the name is CALLED. The name really IS "THE AGED
AGED MAN."'

`Then I ought to have said "That's what the SONG is called"?' Alice
corrected herself.

`No, you oughtn't: that's quite another thing! The SONG is called "WAYS
AND MEANS": but that's only what it's CALLED, you know!'

`Well, what IS the song, then?' said Alice, who was by this time
completely bewildered.

`I was coming to that,' the Knight said. `The song really IS "A-SITTING
ON A GATE": and the tune's my own invention.'

-- Lewis Carroll "Through the Looking Glass".
 
T

Tom Cole

<snip>
^^^
It is not going to work very well with that - new - operator in there.

Thank you...don't know where the new came from :) Should have tested
the code before posting it...
 
T

Thomas 'PointedEars' Lahn

Henry said:
No, it is a property of the object. The value of that property may be
a function, if you assign one to it.

The value of the property may be a reference to a Function object, if you
assign one to it.


PointedEars
 
N

news

How about this (heh):

function rthis() {
return this;

}

rthis(); // returns the global object.
Aye...


var obj = { meth: rthis }; // obj.meth === rthis

obj.meth(); // returns obj

Aye, this is what I expected :)
new rthis(); // returns a new object with rthis.prototype as it's
// prototype

Hmm, I really gotta look more into this prototype-business - it's not
all that clear to me, but I'm beginning to get the idea ;)
So, "this" is always dependent on how the function in question is
called, and nothing else.


As long as there is a reachable reference, yes.

Yeah. I just didn't see any references beeing kept.

Thanks for the help ye all. On a side-note I've been a lot into Java,
but it's the first time I really dove into JavaScript and I was
surprised to find it a lot different in ways. I got thrown right into
it and I see I've got quite a few things to pick up yet :)

Cheers!
 
V

VK

I guess the object lives on somehow anyway?
Yeah. I just didn't see any references beeing kept.

I don't think these answers helped too much... In your original post
you were hitting the incontinence of "this" problem in Javascript.
Some do consider it as a viable language feature, some do consider it
as a language design default. Without going into further discussion of
right and wrong:
Javascript doesn't have "methods" as such. Any function is a top level
oblect, and how will it be threated - and respectively what context
will it have - depends solely and exclusively on the way you call this
function: directly or chained in some object path.

var glbObj = null;

var glbRef = null;

function MyObject(name) {
this.name = name || 'anonymous';
this.sayName = MyObject.sayName;
}

MyObject.sayName = function() {
window.alert(this.name || 'undefined');
}

glbObj = new MyObject('foo');

/* sayName is called as an instance method
* of glbObj, "this" points to the instance
*/
glbObj.sayName(); // "foo"

/* Creating direct reference
* to sayName function object
*/
glbRef = glbObj.sayName;

/* Direct stay-alone function call,
* "this" points to global scope.
*/
glbRef(); // "undefined"

It is easy to guess that such behaviors makes sometimes very difficult
to accomplish timed calls and overall use static (in C++ sense)
methods.

Over years a number of workarounds were found, the most oftenly used
being to freeze the context by closure, so effectively do not use
static methods in Javascript at all. From the point of view of
effective programming and resource usage it is IMO kind of
extinguishing a fire by gas :) :-( - but the things have to be done
somehow, and it is a somehow working way. Many programmers are getting
so upset on Javascript that they abandon prototype hassle all together
and using "closure-based inheritance" everywhere after that, no matter
either it's helping or hurting.
http://groups.google.com/group/comp.lang.javascript/msg/fa5f0379c069ac9c

In case of AJAX the closure workaround is a viable method if one needs
multiple XHRs running at the same time.

function XHR() {
var $this = this;
this.onreadystatechange = function() {
// do your stuff with $this
}
}

You may take a look at AjaxRequest by Matt Kruse for more code
samples:
http://www.ajaxtoolbox.com/request/source.php
 
A

AKS

Javascript doesn't have "methods" as such. Any function is a top level
oblect, and how will it be threated - and respectively what context
will it have - depends solely and exclusively on the way you call this
function: directly or chained in some object path.

For example => Function.prototype.call. Is it a method or not? Could
it be called indirectly?
 
T

Thomas 'PointedEars' Lahn

That is not hard to find out as ECMAScript implementations have been
single-threaded from day one.
For example => Function.prototype.call. Is it a method or not?

It is a method. In ECMAScript implementations, all functions are also
methods. Top-level functions, built-in and user-defined, are methods of the
Global Object.

You are well-advised to ignore VK.
Could it be called indirectly?

Yes, it could:

var o = {
answer: 42
};

var f = function(x) {
window.alert([this.answer, x]);
};

f.c = Function.prototype.call;
f.c(o, 23);

However, there is a provision to Function.prototype.call; the Activation
Object must be a Function object:

var c = Function.prototype.call;
c(o, 42);

throws a TypeError exception.


PointedEars
 
T

Thomas 'PointedEars' Lahn

Thomas said:
AKS said:
For example => Function.prototype.call. [...]
Could it be called indirectly?

Yes, it could:

var o = {
answer: 42
};

var f = function(x) {
window.alert([this.answer, x]);
};

f.c = Function.prototype.call;
f.c(o, 23);

However, there is a provision to Function.prototype.call; the Activation ^^^^^^^^^^^^^^
Object
^^^^^^
That should read "the calling object". The Activation Object instead is the
object that has `arguments' and local variables as its properties and is
purely a specification mechanism; it cannot be accessed by an ECMAScript
program (ES3 Final, 10.1.6).
must be a Function object:

That should read "must implement the internal [[Call]] method" (ES3 Final,
15.3.4.4). Other objects may also implement [[Call]]; nevertheless it is
wrong to assume that host object's methods always do that (ES3 Final, 8.6.2).
var c = Function.prototype.call;
c(o, 42);

throws a TypeError exception.

Since the calling object (the Variable Object of an execution context of
which `c' is a property) does not implement [[Call]].


PointedEars
 

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,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top