views:

113

answers:

2

Hey I have this code right here: http://pastie.org/534470

And on line 109 I get an error saying "TypeError: Result of expression 'this.allVarsDefined' [undefined] is not a function."

Scope in javascript is confusing to me. Can anybody see what my problem is? Also do you guys know of any articles that would help me learn about scope in javascript. This is my first time really using JS :)

A: 

Try changing line 109 from

setTimeout(this.notify, 5000, track);

to

setTimeout(function(){this.notify()}, 5000, track);

What this will do is create "closure" (function(){this.notify()}) that includes the "this" variable in it, and "this" includes this.allVarsDefined, so you should stop getting that error.

I think the problem with your old code is that when you write "this.notify" you were just yanking the function out of the instance of the object and passing it to setTimeout, but you were not passing any information about the object itself. That would be okay if the notify function did not refer to "this", but since it does refer to "this", you need to use a closure.

You would benefit from reading more about Javascript closures. Here is a decent article. I also recommend the great book Java Script: The Definitive Guide 5th Edition by O'Reilly. It only costs like $50 but it is well-written and will help you immensely if you are trying to write a web-app in javascript.

If my solution does not work, then simplify your code down to the most basic thing that you think should work and does not work, and then post it here.

David Grayson
your example will not solve the problem as when the setTimeout runs "this" will refer to the window. see tvanfosson's example for how to do the closure corretly
Jonathan Fingland
+2  A: 

This looks prototype-based. You probably need to set up your notification callback like this:

setTimeout(this.notify.bind(this), 5000, track);

so that the notify function is bound to the Scrobbler object and gets this set to the Scrobbler object instead of the event triggering the function when the timeout occurs.

If I'm wrong on you using prototype, you can probably achieve the same effect using

var that = this;
setTimeout( function() { that.notify(); }, 5000, track );
tvanfosson
correct on both points. bind makes use of .apply and stores the context in a closure. The other one is still making use of closure, and in my opinion a much simpler way to go about it.
Jonathan Fingland