Connecting Tech Pros Worldwide Forums | Help | Site Map

Using timers within OO Javascript

Evan Charlton
Guest
 
Posts: n/a
#1: Aug 4 '07
Hey all, I'm having some trouble with window.setInterval() within a
custom object/prototype. Here is my code:

Expand|Select|Wrap|Line Numbers
  1. function MyClass() {
  2. // do some junk
  3. // ...
  4. // define methods
  5. this.m_one = function() {
  6. // nothing happens with this line. No alert, no errors
  7. window.setInterval( "this.m_two", 500 );
  8. // "error: this.m_two() is not a function"
  9. window.setInterval( "this.m_two()", 500 );
  10. // "error: m_two() is not defined"
  11. window.setInterval( "m_two()", 500 );
  12. // "error: m_two is not defined"
  13. window.setInterval( "m_two", 500 );
  14. // the following one works just fine .
  15. window.setInterval( "timer()", 500 );
  16. }
  17. this.m_two = function() {
  18. alert("m_two");
  19. }
  20. }
  21. function timer() {
  22. alert("timer");
  23. }
  24. var o = new MyClass();
  25. if( confirm( "start?" ) ){
  26. o.m_one();
  27. }
  28.  
I'm stumped on this one; how do I set another method in the object as
the callback?
Thomas 'PointedEars' Lahn
Guest
 
Posts: n/a
#2: Aug 4 '07

re: Using timers within OO Javascript


Evan Charlton wrote:
Quote:
Hey all, I'm having some trouble with window.setInterval() within a
custom object/prototype. Here is my code:
>
[code]
function MyClass() {
Why are people so obsessed with classes when it comes to OOP? From the
above I thought you had understood that ECMAScript 3 implementations use
only prototype-based inheritance.
Quote:
// do some junk
// ...
// define methods
this.m_one = function() {
// nothing happens with this line. No alert, no errors
window.setInterval( "this.m_two", 500 );
Why should there? It is merely a not evaluated read access to the
non-existing property `m_two' *of the Global Object*.
Quote:
// "error: this.m_two() is not a function"
window.setInterval( "this.m_two()", 500 );
This is trying to call a method of the Global Object. Since the
identifier cannot be resolved, you get the runtime error.
Quote:
// "error: m_two() is not defined"
window.setInterval( "m_two()", 500 );
This is trying to call an identifier without an explicit object
reference. Since the identifier cannot be resolved through the scope
chain, you get the runtime error.
Quote:
// "error: m_two is not defined"
window.setInterval( "m_two", 500 );
This is trying to access an identifier without an explicit object
reference. Since the identifier cannot be resolved through the scope
chain, you get the runtime error.

As you can see, you cannot use a locally defined name in a string for
the window.setInterval() method (it would be the same with
window.setTimeout()). However, you can pass a Function object
reference, that is a reference to your method:

window.setInterval(this.m_two, 500);
Quote:
// the following one works just fine .
window.setInterval( "timer()", 500 );
Because timer() is a globally declared function, and (so) a method of
the Global Object. "this.timer()" should work as well.

}
Quote:
this.m_two = function() {
alert("m_two");
}
}
[...]

HTH

PointedEars
--
var bugRiddenCrashPronePieceOfJunk = (
navigator.userAgent.indexOf('MSIE 5') != -1
&& navigator.userAgent.indexOf('Mac') != -1
) // Plone, register_function.js:16
Thomas 'PointedEars' Lahn
Guest
 
Posts: n/a
#3: Aug 4 '07

re: Using timers within OO Javascript


Thomas 'PointedEars' Lahn wrote:
Quote:
As you can see, you cannot use a locally defined name in a string for
the window.setInterval() method (it would be the same with
window.setTimeout()). However, you can pass a Function object
reference, that is a reference to your method:
>
window.setInterval(this.m_two, 500);
Correction, use this instead to retain the method-object relationship:

window.setInterval(function callTwo() { this.m_two(); }, 500);


PointedEars
--
var bugRiddenCrashPronePieceOfJunk = (
navigator.userAgent.indexOf('MSIE 5') != -1
&& navigator.userAgent.indexOf('Mac') != -1
) // Plone, register_function.js:16
Richard Cornford
Guest
 
Posts: n/a
#4: Aug 4 '07

re: Using timers within OO Javascript


Thomas 'PointedEars' Lahn wrote:
Quote:
Thomas 'PointedEars' Lahn wrote:
Quote:
>As you can see, you cannot use a locally defined name in a
>string for the window.setInterval() method (it would be
>the same with window.setTimeout()). However, you can
>pass a Function object reference, that is a reference to
>your method:
>>
> window.setInterval(this.m_two, 500);
>
Correction, use this instead to retain the method-object relationship:
>
window.setInterval(function callTwo() { this.m_two(); }, 500);
That is not going to help because when setInterval executes the function
expression (or the object resulting from the evaluation of the function
expression, to be precise) the - this - reference inside that function
will be to the global object and so - this.m_two - will have the same
meaning as when it was in the string in the earlier examples.

Richard.

jamie.ly@gmail.com
Guest
 
Posts: n/a
#5: Aug 4 '07

re: Using timers within OO Javascript


This function may help you. It is from the Prototype javascript
library. (http://prototypejs.org/api)

Function.prototype.bind = function() {
var __method = this, args = arguments ? arguments : [], object =
args.shift();
return function() {
return __method.apply(object, args.concat(arguments ? arguments :
[]));
}
}

After placing this before the code below you can do this and it should
work:

instead of : window.setInterval( "this.m_two", 500 );
use: window.setInterval( this.m_two.bind ( this ), 500 );

What bind does is copies all of the methods and properties of 'this'
object into the m_two function as a new object. I've modified it a
bit, so if this doesn't work, just add the complete prototype library
from the site listed above.

jamie.ly@gmail.com
Guest
 
Posts: n/a
#6: Aug 4 '07

re: Using timers within OO Javascript


Quote:
After placing this before the code below you can do this and it should
work:
>
instead of : window.setInterval( "this.m_two", 500 );
use: window.setInterval( this.m_two.bind ( this ), 500 );
>
What bind does is copies all of the methods and properties of 'this'
object into the m_two function as a new object. I've modified it a
bit, so if this doesn't work, just add the complete prototype library
from the site listed above.
Alternatively, if you don't need to access any of the class's
properties in "m_two", just do what Thomas said above:
Quote:
As you can see, you cannot use a locally defined name in a string for
the window.setInterval() method (it would be the same with
window.setTimeout()). However, you can pass a Function object
reference, that is a reference to your method:
>
window.setInterval(this.m_two, 500);
Thomas 'PointedEars' Lahn
Guest
 
Posts: n/a
#7: Aug 4 '07

re: Using timers within OO Javascript


Richard Cornford wrote:
Quote:
Thomas 'PointedEars' Lahn wrote:
Quote:
>Thomas 'PointedEars' Lahn wrote:
Quote:
>> window.setInterval(this.m_two, 500);
>Correction, use this instead to retain the method-object relationship:
>>
> window.setInterval(function callTwo() { this.m_two(); }, 500);
>
That is not going to help because when setInterval executes the function
expression (or the object resulting from the evaluation of the function
expression, to be precise) the - this - reference inside that function
will be to the global object and so - this.m_two - will have the same
meaning as when it was in the string in the earlier examples.
True, a closure is required:

this.m_one = function()
{
var me = this;
window.setInterval(function() { me.m_two(); }, 500);
};

this.m_two = function()
{
window.alert(this.m_one);
};


PointedEars
--
Prototype.js was written by people who don't know javascript for people
who don't know javascript. People who don't know javascript are not the
best source of advice on designing systems that use javascript.
-- Richard Cornford, <f806at$ail$1$8300dec7@news.demon.co.uk>
Ralf Beutler
Guest
 
Posts: n/a
#8: Aug 4 '07

re: Using timers within OO Javascript


Thomas 'PointedEars' Lahn schrieb:
Quote:
Thomas 'PointedEars' Lahn wrote:
Quote:
>As you can see, you cannot use a locally defined name in a string for
>the window.setInterval() method (it would be the same with
>window.setTimeout()). However, you can pass a Function object
>reference, that is a reference to your method:
>>
> window.setInterval(this.m_two, 500);
>
Correction, use this instead to retain the method-object relationship:
>
window.setInterval(function callTwo() { this.m_two(); }, 500);
You're wrong!

You definitely need closures for this, if you need access to this object:

function MyClass() {
//..
this.m_one = function() {
var me = this; // create a closure
this.interval = window.setInterval( function(){
me.m_two();
}, 1000 );
}
//..
}

br | rb
--
Sie freuten sich riesig, wenn eine Maschine nach sechs Stunden etwas
fertig brachte, wozu jeder Mensch auf der Straße für 2 Cent fähig
gewesen wäre. Anschließend ließen sie sich Bananen- und Sushi-Pizza
kommen und schliefen vor der Tastatur ein. [aus T.P., Heiße Hüpfer]
Thomas 'PointedEars' Lahn
Guest
 
Posts: n/a
#9: Aug 4 '07

re: Using timers within OO Javascript


jamie.ly@gmail.com wrote:
Quote:
Alternatively, if you don't need to access any of the class's
properties in "m_two", just do what Thomas said above:
[...]
*sigh* *There* *is* *no* *class*. My sig happens to be proved by your
statement.


PointedEars
--
Prototype.js was written by people who don't know javascript for people
who don't know javascript. People who don't know javascript are not the
best source of advice on designing systems that use javascript.
-- Richard Cornford, <f806at$ail$1$8300dec7@news.demon.co.uk>
Richard Cornford
Guest
 
Posts: n/a
#10: Aug 4 '07

re: Using timers within OO Javascript


jamie.ly@gmail.com wrote:
Quote:
This function may help you. It is from the Prototype
javascript library. (http://prototypejs.org/api)
>
Function.prototype.bind = function() {
var __method = this, args = arguments ? arguments : [], object =
args.shift();
return function() {
return __method.apply(object, args.concat(arguments ? arguments :
[]));
}
}
You have got to be joking. That is far too bad even for Prototype.js
code. I know that they have long since broken compatibility with ECMA
262 3rd Ed. but that is not even going to work in common browser
environments.

And what do they think - args = arguments ? arguments : [] - is about?
The existence of an - arguments - object, and that the Identifier
'arguments' will refer to that object, is absolutely guaranteed (short
of jumping through some extreme hoops with things like -
with({arguments:null}){ args = arguments?arguments:[];} -). And even
if - arguemtns - were allowed not exist the code would likely error out
at the first reference to it whenever it didn't. It would be difficult
to make this stuff up if you tried.
Quote:
After placing this before the code below you can do this and
it should work:
>
instead of : window.setInterval( "this.m_two", 500 );
use: window.setInterval( this.m_two.bind ( this ), 500 );
>
What bind does is copies all of the methods and properties of
'this' object into the m_two function as a new object.
No it does not, and if it did that would be a disaster in this context
(and very many others) as the copy would be a copy of the state of the
object at the time of the setInterval call and so the method would end
up acting on an object with a (potentially) out-of-date state, and if it
needed to change the state of its object it would not be able to, but
instead would only change the state of the copy.
Quote:
I've modified it a bit,
So what precisely did you modify? That is, how broken was it before you
started playing with it?
Quote:
so if this doesn't work,
If? When it doesn't work! Opera may be the only browser where this does
work, and that is because of an ECMAScript bug in Opera.
Quote:
just add the complete prototype library
from the site listed above.
Considering how utterly trivial the solution(s) to this problem is(are)
if you understand what you are doing, that has got to be one of the
worst suggestions possible.

Richard.

Richard Cornford
Guest
 
Posts: n/a
#11: Aug 4 '07

re: Using timers within OO Javascript


Thomas 'PointedEars' Lahn wrote:
Quote:
Richard Cornford wrote:
Quote:
>Thomas 'PointedEars' Lahn wrote:
Quote:
>>Thomas 'PointedEars' Lahn wrote:
>>> window.setInterval(this.m_two, 500);
>>Correction, use this instead to retain the method-object
>>relationship:
>>>
>> window.setInterval(function callTwo() { this.m_two(); }, 500);
>>
>That is not going to help because when setInterval executes the
>function expression (or the object resulting from the evaluation
>of the function expression, to be precise) the - this - reference
>inside that function will be to the global object and so -
>this.m_two - will have the same meaning as when it was in the
>string in the earlier examples.
>
True, a closure is required:
A closure is (or probably is) required, but only one.
Quote:
this.m_one = function()
{
var me = this;
window.setInterval(function() { me.m_two(); }, 500);
};
>
this.m_two = function()
{
window.alert(this.m_one);
};
As you have it every call to - m_one - will create a new function object
and a new closure. But if the closure was formed in the constructor (or
by other means (e.g. in an external function), but once only) with the -
m_two - method then the result would be more efficient.

function AnObject(){
var self = this;
this.m_two = function(){
// have this function refer to its object instance through the
// scope chain instead of through the - this - keyword and
// you only need one instance of this function
alert(self.m_one);
};
}

// and - m_one - does not need to created in the constructor
AnObject.prototoype.m_one = function(){
setInterval(this.m_two, 500);
};

And if the idea of creating the closure at the time of instantiation the
object did not appeal the 'Russian Doll' pattern (or similar) could be
applied to create it once, but at the first call to - m_one -.

function AnObject(){
}

AnObject.prototoype.m_two = function(){
alert(this.m_one);
};

AnObject.prototoype.m_one = function(){
var self = this;
function atIntervals(){
self.m_two();
}
(this.m_one = function(){
// This is the function that calls to - obj.m() - once use
directly
// following its indirect use in the first call.
setInterval(atIntervals, 500);
})();
};
Quote:
Prototype.js was written by ...
One of my gripes about Prototype.js is the way in which it encourages
(even forces) horrendously inefficient use of functions, and especially
functions that are 'bound' to objects. You will often see Prototype.js
code where in real javascript you cold define/use a single instance of a
function and re-use it to your hart's content being implemented so that
a new function object is created on each and every use, or worse, a new
function created and then another with its own closure as the first is
'bound' to some object, but the same object on each occasion.

Richard.

Closed Thread


Similar JavaScript / Ajax / DHTML bytes