By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,851 Members | 1,051 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,851 IT Pros & Developers. It's quick & easy.

setTimeout(this.doAnimation, 1000) will fail if it is defined in aclass definition

P: n/a
I did some animation using
var oDiv = {};
oDiv.x = 100;
oDiv.y = 100;
oDiv.node = document.getElementById('divImage');
oDiv.node.style.position = "absolute";

oDiv.doAnimation = function() {
oDiv.x += 1;
oDiv.y += 1;
oDiv.node.style.top = oDiv.y + 'px';
oDiv.node.style.left = oDiv.x + 'px';
setTimeout(oDiv.doAnimation, 33);
}
and it works fine. When it is changed to the traditional class
definition, then it fails:
function Animation() {
this.x = ...
etc...

this.doAnimation = function() {
// do something

// set delay
setTimeout(this.doAnimation, 33);
}
}

oDiv = new Animation();
oDiv.doAnimation();
which will fail. The second time when the doAnimation() is called, it
seems that it doesn't have a concept of this.x, etc.

It is the same if I use the more popular way of defining a class by
moving the function out:
function Animation() {
this.x = ...
etc...
}

Animation.prototype.doAnimation = function() {
// do something
}
and it is the same, the second time when doAnimation() is invoked by
the setTimeout, it doesn't have a concept of this.x.

Does someone know what it is? hm... I don't need to use prototype.js
and use something like doAnimation.bind(this) ? Can it be a self-
contained script that doesn't rely on other framework? Thanks.

Oct 4 '08 #1
Share this Question
Share on Google+
19 Replies


P: n/a
liketofindoutwhy meinte:
and it works fine. When it is changed to the traditional class
definition, then it fails:
There are no classes in JS.
>
function Animation() {
this.x = ...
etc...

this.doAnimation = function() {
// do something

// set delay
setTimeout(this.doAnimation, 33);
}
}

oDiv = new Animation();
oDiv.doAnimation();
which will fail. The second time when the doAnimation() is called, it
seems that it doesn't have a concept of this.x, etc.
[snip]
Does someone know what it is?
You need a closure. Google "javascript closure" and read.

You will eventually end up with something like

var that = this;
....
window.setTimeout(that.doAnimation, 33);

Gregor
--
http://photo.gregorkofler.at ::: Landschafts- und Reisefotografie
http://web.gregorkofler.com ::: meine JS-Spielwiese
http://www.image2d.com ::: Bildagentur fr den alpinen Raum
Oct 4 '08 #2

P: n/a
Gregor Kofler wrote:
liketofindoutwhy meinte:
>function Animation() {
this.x = ...
etc...

this.doAnimation = function() {
// do something

// set delay
setTimeout(this.doAnimation, 33);
}
}

oDiv = new Animation();
oDiv.doAnimation();
which will fail. The second time when the doAnimation() is called, it
seems that it doesn't have a concept of this.x, etc.

[snip]
Does someone know what it is?

You need a closure. Google "javascript closure" and read.

You will eventually end up with something like

var that = this;
...
window.setTimeout(that.doAnimation, 33);
Should be

window.setTimeout(function() { that.doAnimation() }, 33);

because with your code the method loses its connection to `that' (being
passed as just another Function object reference) and `this' in its
execution context will again refer to the Window or Global Object instead.
PointedEars
--
var bugRiddenCrashPronePieceOfJunk = (
navigator.userAgent.indexOf('MSIE 5') != -1
&& navigator.userAgent.indexOf('Mac') != -1
) // Plone, register_function.js:16
Oct 4 '08 #3

P: n/a
Thomas 'PointedEars' Lahn meinte:
Gregor Kofler wrote:
>window.setTimeout(that.doAnimation, 33);

Should be

window.setTimeout(function() { that.doAnimation() }, 33);
Oops. Sorry. My bad. My version does exactly _not_ create a closure.

Gregor
--
http://photo.gregorkofler.at ::: Landschafts- und Reisefotografie
http://web.gregorkofler.com ::: meine JS-Spielwiese
http://www.image2d.com ::: Bildagentur für den alpinen Raum
Oct 4 '08 #4

P: n/a

wow, that's a lot of this and that... and by the way, is it just
Javascript? Do other language automatically say... ok... it is
this.doAnimation, so when I call doAnimation, I will make sure it is
applied on the current object "this" is referring to.
by the way, someone gave me a solution (besides using Prototype.js
setTimeout(this.doAnimation.bind(this), 33);

define a global function:

function bindIt(obj, func) {
return function() { func.apply(obj) }
}

and then use

setTimeout(bindIt(this, this.doAnimation), 33);

Oct 5 '08 #5

P: n/a
On Oct 5, 11:25*pm, liketofindoutwhy <liketofindout...@gmail.com>
wrote:
wow, that's a lot of this and that... *and by the way, is it just
Javascript? *Do other language automatically say... ok... it is
this.doAnimation, so when I call doAnimation, I will make sure it is
applied on the current object "this" is referring to.

by the way, someone gave me a solution (besides using Prototype.js
setTimeout(this.doAnimation.bind(this), 33);

define a global function:

* * * * function bindIt(obj, func) {
* * * * * * return function() { func.apply(obj) }
* * * * }

and then use

setTimeout(bindIt(this, this.doAnimation), 33);
You could as well do:

function Animation () {
var that= this;
this.x = ...
etc...
this.doAnimation = function () {
//use 'that' instead of 'this'
// do something
// set delay
setTimeout(arguments.callee, 33);
};
};

but then doAnimation() is permanently bound to 'that'.

--
Jorge.
Oct 5 '08 #6

P: n/a
liketofindoutwhy wrote:
wow, that's a lot of this and that... and by the way, is it just
Javascript? Do other language automatically say... ok... it is
this.doAnimation, so when I call doAnimation, I will make sure it is
applied on the current object "this" is referring to.
You have failed to phrase an intellible question.
by the way, someone gave me a solution (besides using Prototype.js
setTimeout(this.doAnimation.bind(this), 33);

define a global function:

function bindIt(obj, func) {
return function() { func.apply(obj) }
}

and then use

setTimeout(bindIt(this, this.doAnimation), 33);
That's (Prototype.js) junk, not a solution. To begin with, it requires
Function.prototype.apply() to be supported, or it breaks, needlessly.
PointedEars
--
Use any version of Microsoft Frontpage to create your site.
(This won't prevent people from viewing your source, but no one
will want to steal it.)
-- from <http://www.vortex-webdesign.com/help/hidesource.htm>
Oct 6 '08 #7

P: n/a
On Oct 5, 4:16 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
Gregor Kofler wrote:
liketofindoutwhy meinte:
function Animation() {
this.x = ...
etc...
this.doAnimation = function() {
// do something
// set delay
setTimeout(this.doAnimation, 33);
}
}
oDiv = new Animation();
oDiv.doAnimation();
which will fail. The second time when the doAnimation() is called, it
seems that it doesn't have a concept of this.x, etc.
[snip]
Does someone know what it is?
You need a closure. Google "javascript closure" and read.
You will eventually end up with something like
var that = this;
...
window.setTimeout(that.doAnimation, 33);

Should be

window.setTimeout(function() { that.doAnimation() }, 33);

because with your code the method loses its connection to `that' (being
passed as just another Function object reference) and `this' in its
execution context will again refer to the Window or Global Object instead.
I'm still not sure about one thing. Why doesn't
window.setTimeout(this.doAnimation,33) work? Is it because of the fact
that when JavaScript interpreter will come across this line it will
set "this" in "this.doAnimation" line to global window object as
setTimeout() is a method of global object? Does that sound good?
Moreover, having a closure like window.setTimeout(function()
{that.doAnimation()},33) works because Closures remember their context
and this is why "that" will point to correct "this"?

Can you please expand on that a bit? I will appreciate your help.

Thanks.
PointedEars
--
var bugRiddenCrashPronePieceOfJunk = (
navigator.userAgent.indexOf('MSIE 5') != -1
&& navigator.userAgent.indexOf('Mac') != -1
) // Plone, register_function.js:16
Oct 6 '08 #8

P: n/a
On Oct 6, 8:06 pm, Oltmans <rolf.oltm...@gmail.comwrote:
>
I'm still not sure about one thing. Why doesn't
window.setTimeout(this.doAnimation,33) work? Is it because of the fact
that when JavaScript interpreter will come across this line it will
set "this" in "this.doAnimation" line to global window object as
setTimeout() is a method of global object?
No.

1.- Functions are objects, and the objects are passed by reference.
setTimeout expects (as a parameter) a reference to a function.

2.- 'this.doAnimation' is a property (of the object that 'this' points
to) that happens to hold a reference to a function.

3.- It is that reference what gets passed to setTimeout, and it holds
no relation with 'this' nor with the object that 'this' points to nor
with its 'doAnimation' property. That we have read it in the property
'doAnimation' of the object that 'this' points to, it doesn't matter.
Where it comes from is a don't care, it's just a reference to a
function.

Moreover, having a closure like window.setTimeout(function()
{that.doAnimation()},33) works because Closures remember their context
and this is why "that" will point to correct "this"?
1.- As the function (*) 'function() {that.doAnimation()}' has been
created in the context of the outer function, it too has access to the
same context.

2.- As long as a reference to that function (*) exists (in this case,
the reference that exists is the one passed to setTimeout), the
context won't/can't be destroyed by the garbage collector.

3.- And as 'that' is defined in the context, it's accesible from the
function (*) as well.

--
Jorge.
Oct 6 '08 #9

P: n/a
On Oct 6, 11:10*pm, Jorge <jo...@jorgechamorro.comwrote:
On Oct 6, 8:06 pm, Oltmans <rolf.oltm...@gmail.comwrote:
I'm still not sure about one thing. Why doesn't
window.setTimeout(this.doAnimation,33) work? Is it because of the fact
that when JavaScript interpreter will come across this line it will
set "this" in "this.doAnimation" line to global window object as
setTimeout() is a method of global object?

No.

1.- Functions are objects, and the objects are passed by reference.
setTimeout expects (as a parameter) a reference to a function.

2.- 'this.doAnimation' is a property (of the object that 'this' points
to) that happens to hold a reference to a function.

3.- It is that reference what gets passed to setTimeout, and it holds
no relation with 'this' nor with the object that 'this' points to nor
with its 'doAnimation' property. That we have read it in the property
'doAnimation' of the object that 'this' points to, it doesn't matter.
Where it comes from is a don't care, it's just a reference to a
function.
And:

4.- If we call 'f' the reference to a function, then that's what your
code does:

this.doAnimation= f; -setTimeout(this.doAnimation, 33) ===
setTimeout(f, 33) -when setTimeout times out it calls f().

--
Jorge.
Oct 6 '08 #10

P: n/a
Oltmans wrote:
Thomas 'PointedEars' Lahn wrote:
>Gregor Kofler wrote:
>>var that = this;
...
window.setTimeout(that.doAnimation, 33);
Should be

window.setTimeout(function() { that.doAnimation() }, 33);

because with your code the method loses its connection to `that' (being
passed as just another Function object reference) and `this' in its
execution context will again refer to the Window or Global Object instead.

I'm still not sure about one thing. Why doesn't
window.setTimeout(this.doAnimation,33) work?
I thought I had explained that above already.
Is it because of the fact that when JavaScript interpreter will come
across this line it will set "this" in "this.doAnimation" line to
global window object as setTimeout() is a method of global object?
No. First of all, the JavaScript interpreter (Virtual Machine) does not see
any of this. JavaScript source code is compiled into byte-code, which is
then interpreted/executed by a VM, just like Java (only that it is usually
JIT-compilation with JS).

Second, the compiler does not modify the meaning of symbols based on their
context. It is instead that if you pass `this.doAnimation' you are merely
passing a Function object reference (provided that `this.doAnimation' refers
to a Function object). When this Function object is called (here: by the
object referred to by `window') there is no telling which object's property
referred to it. So the `this' value initially does not refer to any object
(`null') which means that it is then set to the Global Object (that is not
necessarily the same as the object referred to by `window'). And that
object does not have a `doAnimation' property in either case.
Does that sound good?
Unfortunately, no.
Moreover, having a closure like window.setTimeout(function()
{that.doAnimation()},33) works because Closures remember their context
and this is why "that" will point to correct "this"?
Not quite. The function (expression) creates a closure, because there is
literally a bound variable here, `that'. It is a bound variable because
that variable is declared outside the function, and therefore its usage is
bound to that outer area. That outer area is the closure's definition
context (the context in which it was defined). That context is reproduced
when the function is called. Since `that' is (the identifier of) a variable
that has been assigned the `this' value within the definition context, it
stores a reference to the same object that `this' referred to, there and
then. That reference -- no pun intended -- can be used within the called
function then, no matter the caller.

Please trim your quotes to the necessary minimum, as you can see here.
PointedEars
--
var bugRiddenCrashPronePieceOfJunk = (
navigator.userAgent.indexOf('MSIE 5') != -1
&& navigator.userAgent.indexOf('Mac') != -1
) // Plone, register_function.js:16
Oct 6 '08 #11

P: n/a
Jorge wrote:
On Oct 6, 8:06 pm, Oltmans <rolf.oltm...@gmail.comwrote:
>I'm still not sure about one thing. Why doesn't
window.setTimeout(this.doAnimation,33) work? Is it because of the fact
that when JavaScript interpreter will come across this line it will
set "this" in "this.doAnimation" line to global window object as
setTimeout() is a method of global object?

No.

1.- Functions are objects, and the objects are passed by reference.
No, all arguments are passed by value; object references are values.[1]
setTimeout expects (as a parameter) a reference to a function.
Or a string value, whereas the latter is slightly more compatible.
2.- 'this.doAnimation' is a property (of the object that 'this' points
to) that happens to hold a reference to a function.
[1^] See?
2.- As long as a reference to that function (*) exists (in this case,
the reference that exists is the one passed to setTimeout), the
context won't/can't be destroyed by the garbage collector.
True, however an implementation is free to provide a copy instead of a
reference, which would allow the source of this copy to be marked for
garbage collection.
PointedEars
--
var bugRiddenCrashPronePieceOfJunk = (
navigator.userAgent.indexOf('MSIE 5') != -1
&& navigator.userAgent.indexOf('Mac') != -1
) // Plone, register_function.js:16
Oct 6 '08 #12

P: n/a
On Oct 7, 4:17 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
Not quite. The function (expression) creates a closure, because there is
literally a bound variable here, `that'. It is a bound variable because
that variable is declared outside the function, and therefore its usage is
bound to that outer area. That outer area is the closure's definition
context (the context in which it was defined). That context is reproduced
when the function is called. Since `that' is (the identifier of) a variable
that has been assigned the `this' value within the definition context, it
stores a reference to the same object that `this' referred to, there and
then. That reference -- no pun intended -- can be used within the called
function then, no matter the caller.
OK. Thank you for explaining this. Very helpful. One last question.
setTimeout() expects function as its first argument. I guess both of
the following will work

a) window.setTimeout(aFunc,50);
where aFunc is defined as

function aFunc(){
alert('you will see me again');
}

b) window.setTimeout(function(){alert('you will see me again');},50);

My question is that if we can pass the Function Object Reference as
depicted in (a) then is it simply replaced with the function body e.g.
aFunc will be relpaced with the function aFunc(){alert('you will see
me again');}.

I mean if both (a) and (b) can do the job then why are there two ways
to do the same thing in the language. Any examples where passing
"Function object references" makes a difference while coding the
function as a parameter doesn't or vice-versa?

Please pardon my ignorance but I really am not sure about this.
Oct 7 '08 #13

P: n/a
dhtml wrote:
Oltmans wrote:
>On Oct 7, 4:17 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
nymous' function.

The former has an advantage in that if you want to say, remove an event
listener.

aDiv.addEventListener('click', aFunc, true);

If an anonymous function were used, it would not be possible to remove
it like so:-

aDiv.removeEventListener('click', aFunc, true);


Well technically the fucntion reference can be retained, but only
through being called:-

var b = document.body;
b.addEventListener('click', function(e){
alert(e);
b.removeEventListener('click', arguments.callee, false);
}, false);

by using arguments.callee in the call.
Oct 7 '08 #14

P: n/a
On Oct 7, 4:41 am, Oltmans <rolf.oltm...@gmail.comwrote:
>
OK. Thank you for explaining this. Very helpful. One last question.
setTimeout() expects function as its first argument. I guess both of
the following will work

a) window.setTimeout(aFunc,50);
where aFunc is defined as

function aFunc(){
alert('you will see me again');

}

b) window.setTimeout(function(){alert('you will see me again');},50);

My question is that if we can pass the Function Object Reference as
depicted in (a) then is it simply replaced with the function body e.g.
aFunc will be relpaced with the function aFunc(){alert('you will see
me again');}.

I mean if both (a) and (b) can do the job then why are there two ways
to do the same thing in the language. Any examples where passing
"Function object references" makes a difference while coding the
function as a parameter doesn't or vice-versa?

1.- A new, distinct instance of a function is created whenever a
function expression is encountered:

var fCollection= [], n= 1;

do {
fCollection[n]= function () { ; };
} while (n--)

alert(fCollection[0] === fCollection[1]); -false

But:

var fCollection= [], n= 1, f= function () { ; };

do {
fCollection[n]= f;
} while (n--)

alert(fCollection[0] === fCollection[1]); -true (obviously)
2.- Even when it's 'coded as a parameter', a reference to it is what
gets passed.

3.- The function 'coded as a parameter' gets created in the context in
which the function expression appears.

3.- Therefore, when 'coded as a parameter' you can tell for sure that
the function that gets passed has access to the context from which
you're passing it.

4.- But that might not be so if you're passing a function that was
created previously (one not 'coded as a parameter'):

function alertName () {
alert(typeof aName);
};

function test () {
var aName= "ok";
setTimeout(alertName, 0);
};

test(); -"undefined"

But:

function test () {
var aName= "ok";
function alertName () {
alert(typeof aName);
};
setTimeout(alertName, 0);
};

test(); -"string"

--
Jorge.
Oct 7 '08 #15

P: n/a
On Oct 7, 1:17 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
>
(..) The function (expression) creates a closure, because there is
literally a bound variable here, `that'. (..)

This phrase is a bit misleading: closures are created regardless of
variables, whenever an inner function is created in a context and it's
made available from outside of the context, and not because "there is
literally a bound variable".

<script>
window.onload= function () {
var that= '"that" is captured in a closure';

//No bound variables in the function expression:
setTimeout(function(){ alert(eval('th'+'at')) },500);
};
</script>

--
Jorge.
Oct 7 '08 #16

P: n/a
On Oct 7, 8:08 am, dhtml <dhtmlkitc...@gmail.comwrote:
>
Well technically the function reference can be retained, but only
through being called:-

var b = document.body;
b.addEventListener('click', function(e){
alert(e);
b.removeEventListener('click', arguments.callee, false);

}, false);

by using arguments.callee in the call.
Or saving a reference to it in the enclosing context:

var b= document.body, fReference;

b.addEventListener('click', (fReference= function(e){
alert(e);
b.removeEventListener('click', fReference, false);
}), false);

--
Jorge.
Oct 7 '08 #17

P: n/a
On Oct 7, 10:56 pm, Jorge <jo...@jorgechamorro.comwrote:
On Oct 7, 8:08 am, dhtml <dhtmlkitc...@gmail.comwrote:
Or saving a reference to it in the enclosing context:

var b= document.body, fReference;

b.addEventListener('click', (fReference= function(e){
alert(e);
b.removeEventListener('click', fReference, false);

}), false);

--
Jorge.
Thank you, Jorge and dhtml. Appreciate your time and help.
Oct 8 '08 #18

P: n/a
Jorge wrote:
Thomas 'PointedEars' Lahn wrote:
>(..) The function (expression) creates a closure, because there is
literally a bound variable here, `that'. (..)

This phrase is a bit misleading: closures are created regardless of
variables, whenever an inner function is created in a context and it's
made available from outside of the context, and not because "there is
literally a bound variable".
"Literally" is merely emphasizing the fact that it does not need to be a
variable in ECMAScript implementations:

<http://en.wikipedia.org/wiki/Closure_%28programming%29>
<script>
window.onload= function () {
var that= '"that" is captured in a closure';

//No bound variables in the function expression:
setTimeout(function(){ alert(eval('th'+'at')) },500);
};
</script>
Your example is not Valid and it is error-prone. That aside, `that' *is*
the bound variable here. It does not matter that the identifier does not
occur as-is in the source code of the called function.
PointedEars
--
Use any version of Microsoft Frontpage to create your site.
(This won't prevent people from viewing your source, but no one
will want to steal it.)
-- from <http://www.vortex-webdesign.com/help/hidesource.htm>
Oct 8 '08 #19

P: n/a
On Oct 8, 12:09*pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
Jorge wrote:
Thomas 'PointedEars' Lahn wrote:
(..) *The function (expression) creates a closure, because there is
literally a bound variable here, `that'. (..)
This phrase is a bit misleading: closures are created regardless of
variables, whenever an inner function is created in a context and it's
made available from outside of the context, and not because "there is
literally a bound variable".

"Literally" is merely emphasizing the fact that it does not need to be a
variable in ECMAScript implementations:

<http://en.wikipedia.org/wiki/Closure_%28programming%29>
Shorter, clearer, easier to understand, in a word : (Mmmuch) better,
explanation:

Closure

Functions can be defined inside of other functions. The inner function
has access to the vars and parameters of the outer function. If a
reference to an inner function survives (for example, as a callback
function), the outer function's vars also survive.

http://javascript.crockford.com/survey.html

HTH,
--
Jorge.
Oct 9 '08 #20

This discussion thread is closed

Replies have been disabled for this discussion.