The Author Online Book Forums are Moving

The Author Online Book Forums will soon redirect to Manning's liveBook and liveVideo. All book forum content will migrate to liveBook's discussion forum and all video forum content will migrate to liveVideo. Log in to liveBook or liveVideo with your Manning credentials to join the discussion!

Thank you for your engagement in the AoF over the years! We look forward to offering you a more enhanced forum experience.

jeffw (3) [Avatar] Offline
#1
I understand how Function.call() works, but I'm a little unclear about why you choose to use it in some situations. In particular, I'm a bit confused about why you used it in this part listing 3.1:

...
var loader=this;
this.req.onreadystatechange=function(){
loader.onReadyState.call(loader);
}
...

Since loader refers to this (the ContentLoader object), couldn't you just say

loader.onReadyState();

instead of using call() ? Wouldn't this be the same in both cases? If not, what would this refer to when using loader.onReadyState(); ? I am familiar with the definitions of the call() and apply() methods, but I'm struggling to understand why they're used in situations like this one.

Thanks for your help. I'm enjoying the book thus far.
Pascarello (208) [Avatar] Offline
#2
Re: another question about ContentLoader and call object context
Did you see the thread that Chester just pulled from the dead?

http://www.manning-sandbox.com/thread.jspa?forumID=179&threadID=15483

Eric
jeffw (3) [Avatar] Offline
#3
Re: another question about ContentLoader and call object context
Yes, I've seen that post, but the situation here seems slightly different from what I'm asking. Namely, in the case of

this.onload.call(this);

onload refers to a function that was passed as a parameter to the ContentLoader constructor, so if you called this.onload(), "this" would refer to the parent object in which whatever function onload refers to was defined. (Right? I'm a bit foggy about that, to be honest. Seems like "this" would be the calling object that invokes onload(), but that's not what the explanation said. While we're at it, why isn't that the case? If "this" refers to the ContentLoader object and I call this.onload(), shouldn't the context be the ContentLoader object, regardless of where the function is defined? I'm less bothered by this than the other case, though.)

However, in the case of

loader.onReadyState.call(this);

the function onReadyState() is defined in the prototype of ContentLoader. This is different from onload, which refers to a function passed as an argument. So why not just use

loader.onReadyState();

? Sorry if you already answered this specific question, but I didn't see a reply to Chester's post that you linked to -- just someone else asking the same question that I am. Do you have an answer for us?
jeffw (3) [Avatar] Offline
#4
Re: another question about ContentLoader and call object context
Actually, the more I think about it, the less necessary

this.onload.call(this);

seems. I was looking at David Flanagan's JavaScript: The Definitive Guide, and in the section on functions as methods (8.4), he says, "The this keyword is important. Any function that is used as a method is effectively passed an implicit argument -- the object through which it is invoked."

So when I say

this.onload = onload;

I'm effectively making onload a method of the ContentLoader object, right? And thus from another method of ContentLoader, if I say

this.onload();

then I'm using onload as a method of ContentLoader (this), right? And the "this" context passed to the function referenced by onload should be the ContentLoader object, right? I don't see how passing the function as an argument changes any of that, regardless of where the passed function was originally defined, but then again I'm new to OO JavaScript (but not OO programming in general), so I could be way off here.

I wrote a very simple test to see if I was obviously wrong:

function DogConstruct(id, fn) {
this.id = id + "_dog";
this.fn = fn;
}

DogConstruct.prototype={
whoDat:function(){
this.fn();
}
}

function CatConstruct(id) {
this.id = id + "_cat";
}

CatConstruct.prototype.catCall=function(){
alert("my " + this.id);
}

window.onload = function() {
var cat = new CatConstruct("jeezy");
var dog = new DogConstruct("fido", cat.catCall);
dog.whoDat();
}


When the page loads, I get an alert box that says "my fido_dog," despite the fact that the catCall function was passed as an argument to the DogConstruct constructor, and despite the fact that I used this.fn() instead of this.fn.call(this). I also tried this example passing a global function to DogConstruct(), and it worked the same.

So... is my test off base, have I misunderstood some nuance, or what? Or were the authors being unnecessarily cautious with this.onload.call(this)?
Pascarello (208) [Avatar] Offline
#5
Re: another question about ContentLoader and call object context
Dave wrote this so I am not sure what was in his head at the time when he wrote this code.

But I have a feeling I know what was happening.

Yes you are right you could call either

loader.onReadyState.call(loader);
or
loader.onReadyState();

and it have the same results.

I think the reason why Dave did it is he may have had the plans to add an override like the onload and the onerror. In that case if you would have stored a function into that (like the onload and onerror can) than you would have to use call(loader).

loader.(myOwnDefinedFunctionUnderTheSheets).call(loader);

That is my guess why it is the way it is.

Eric
Chester (3) [Avatar] Offline
#6
Re: another question about ContentLoader and call object context
In the thread
http://www.manning-sandbox.com/thread.jspa?forumID=179&threadID=15483
Pavan Keely explained that we use the expression
this.onload.call(this)
because this.onload refers to a function defined outside the object and that therefore "this" refers to the window object.

This satisfied me at the time because I accepted it without really thinking about it. But now, unfortunately (I say unfortunately because it has re-opened this can of worms inside my head), I've read jeffw's discussion and it makes me come to the conclusion that the convolution this.onload.call(this) is not necessary, i.e., that a simple this.onload() will suffice. In fact, he seems to have proved it with his simple code experiment.


Eric, you mentioned that Dave wrote the code and that you aren't sure what he was thinking at the time, but would it be possible to get him to address this thread? As jeffw said, there may be some nuance that he was addressing that we are completely overlooking.

CHESTER
kurinosuke (156) [Avatar] Offline
#7
Re: another question about ContentLoader and call object context
I'm a bit confused too, as I thought we did not need to do it that way when using the prototype.
davecrane (149) [Avatar] Offline
#8
Re: another question about ContentLoader and call object context
Hi all,

You're right, writing:

this.onload.call(this)

is exactly the same as writing

this.onload()

only more verbose and confusing. In the interests of history, the reason why it is there is that I originally passed a reference to the XHR object as the context object for the onload callback, i.e.

this.onload.call(xhr)

in which case, using call() makes sense. I then decided that it would be more useful for the callback to have access to the full ContentLoader object, not just the XHR (I think the crunch came in the notifications chapter - it needed to present a message saying which URL had failed), so I swapped out xhr for this, and didsn't stop to look at the full expression, which could now be made shorter.

Hope that's clearer now, sorry for any confusion.

Dave
kurinosuke (156) [Avatar] Offline
#9
Re: another question about ContentLoader and call object context
Thank you !