Edit: This explains it better than I did:
http://bonsaiden.github.com/JavaScript-Garden/#function.this
Your example gives this output on my machine:
waiting
undefined undefined
waiting
undefined undefined
First, constructors shouldn't return anything, so remove the return this line. The reason is because new creates the new object and the constructor merely populates it.
Inside the constructor, this is bound to the object you're creating and normal variables have local scope as usual. This means you have to say this.timeDelayed etc. in the constructor -- else your two variables will fall out of scope when the constructor exits and won't show up as fields or anything later.
With these changes, my output matches yours:
waiting
0 10
waiting
undefined undefined
So now onto your problem.
setTimeout queues a function to run. Functions are just functions -- they don't carry extra information about which object they apply to, even if you treat them as methods (like this.wait does). This plays badly with this because in Javascript, the this keyword asways has dynamic scope, which means the caller gets to pick what it means through something like
someobject.foo()
or whatever. Inside the call to foo, this is bound to someobject. If we took it out:
var foo = someobject.foo
foo()
inside foo, this would be undefined. To make it work, we'd have to say:
foo.call(someobject)
This is important because setTimeout doesn't set the value of this when the timeout function runs. Instead, replace your call:
setTimeout this.wait, 100
with something like:
self = this
setTimeout (-> self.wait()), 100
This works because the function no longer calls this, it calls self which is an ordinary variable.
Coffeescript includes a few tricks and shortcuts here. First, you can avoid capturing self in a closure by using the fat arrow syntax, which automatically binds this in the function to the current object no matter where it's referenced:
Second, you can use @ as a shortcut for this. to write instance variables/methods. Thus, my final code sample looks like:
WaitModel = ->
@timesDelayed = 0
@maxDelay = 10
WaitModel.prototype =
wait: ->
console.log 'waiting'
console.log @timesDelayed, @maxDelay
if @timesDelayed >= @maxDelay
console.log 'running'
@timesDelayed = 0
else
@timesDelayed++
setTimeout (=> @wait()), 100
return
new WaitModel().wait()
setTimeout this.wait, 1000, the variablethisno longer refers to that instance of WaitModel