Help using setInterval within an object function

M

marktm

Hi-

I am trying to use setInterval to call a method within an object and
have not had any luck. I get "Object doesn't support this property or
method" when I execute the following code. What I am doing wrong?

Your help will be much appreciated.
Thanks


<script language="Javascript">

function someObject(){
}

someObject.prototype.showNext = function(){
alert('listening...');
}

//i've tried this:
someObject.prototype.startListening = function(){
this.interval = setInterval('this.showNext()', 2000);
}

//and this:
someObject.prototype.startListening = function(){
this.interval = setInterval(this.showNext(), 2000);

/*

is 'this.showNext()' referencing setInterval and not my object?

*/


}


var x = new someObject();
x.startListening();

</script>
 
B

Baconbutty

I am not sure that this helps, but:-

OPTION 1
this.interval = setInterval(this.showNext(), 2000);

Remove the ( ) as these call the function. You want to pass a reference
to the function instead, thus:

this.interval = setInterval(this.showNext, 2000);

OPTION 2

Use a closure:-

someObject.prototype.startList­ening = function()
{
this.interval = setInterval(showNext, 2000);

function showNext()
{
alert('listening...');
}
}

Julian
 
R

Richard Cornford

marktm said:
I am trying to use setInterval to call a method within an
object and have not had any luck. I get "Object doesn't
support this property or method" when I execute the
following code. What I am doing wrong?
<script language="Javascript">

The language attribute of script elements is deprecated in HTML 4, and
the type attribute is required (rendering the language attribute
redundant). Only attempting to script formally valid HTML removes an
entire category of potential cross-browser scripting pitfalls (saves a
lot of effort and trouble in the long run), but the script elements
themselves need to be valid in order not to have the validator flag them
as erroneous:-

function someObject(){
}

someObject.prototype.showNext = function(){
alert('listening...');
}

//i've tried this:
someObject.prototype.startListening = function(){
this.interval = setInterval('this.showNext()', 2000);

Strings used as the first argument to setTimout/Interval are evaluated
and executed in the global scope, and in the global scope the - this -
keyword is a reference to the global object. The global object does not
have a - showNext - method (unless you give it one) so that code will
error, as described.
}

//and this:
someObject.prototype.startListening = function(){
this.interval = setInterval(this.showNext(), 2000);

But the behaviour was different here as this code put up the alert box,
it did so when the setInterval function was fist called (and only once).

This expression has called the - showNext - method of the object
instance and it is the return value form that function call that is
passed to the setInterval function as an argument. The - showNext -
method returns - undefined - so the first argument to the setInterval
function will likely be type converted into the string "undefined",
which is a pointless expression when executed in the global context on
more modern browsers, and an error (E.G.: IE 4 -> "undefined is
undefined") on older ones.
/*

is 'this.showNext()' referencing setInterval and not my object?

setInterval/Timeout has no knowledge of the context in which it is used.
It's arguments are either a string that will be evaluated/executed in
the global context, or a function reference where the function will be
executed as a function (not as a method of an object, i.e. the - this -
keyword will always refer to the global object).
}

var x = new someObject();
x.startListening();

</script>

If the desire is to retain the association of the function call with an
object instance (which is not worthwhile unless the method called
actually refers to an object instance (uses the - this - keyword)), then
with string arguments a globally accessible reference to the object
instance would need to be created (or an existing one used). In this
case you have a global variable - x - referring to the object instance
so:-

setInterval( "x.showNext();", 1000);

- would work, but be a terrible design as it would have made a detail of
how the object was to be used internal to the object, and you would only
be able to ever use one instance of the object (suggesting an entirely
difference approach from the outset).

To be useful the string argument would need to know how to refer to
distinct object instances without any interest in how those objects were
being employed by external code (anonymously).

This can be done, for example, by having each object constructed create
an unique global reference to itself. E.G:-

function someObject(){
this.index = someObject.instances.length;
someObject.instances[this.index] = this;
}

someObject.instances = [];

someObject.prototype.startListening = function(){
this.interval = setInterval(
'someObject.instances['+this.index+'].showNext()',
2000
);
}

- Which is a bit cumbersome, and leaves you with an array of all objects
created (so they will not be garbage collected if otherwise freed,
unless an explicit 'destroy' facility is provided and used to remove the
references from the globally accessible array).

Using function references as the first argument to setTimeout/Interval,
while preserving the association with an object instance, is simpler to
arrange and more complex to understand as it requires closures. See:-

<URL: http://jibbering.com/faq/faq_notes/closures.html >

And some older browsers do not understand function references as the
first argument to the setTimeout/Interval functions, only strings
(though that can be worked around).

Richard.
 
B

Baconbutty

OPTION 3

Sorry, taking account of what Richard has said, a more accurate example
of a closure would be:-

someObject.prototype.showNext = function()
{
alert('listening...');
};

someObject.prototype.startList­­ening = function()
{
var oInstance=this; // CAPTURE THIS

this.interval = setInterval(function(){oInstance.showNext()},
2000);
// oINSTANCE IS "CLOSED" INSIDE THE ANONYMOUS FUNCTION
};
 
J

Jimnbigd

Use the 2nd way, but leave off the parentheses:
this.interval = setInterval(this.showNext, 2000);
Reason:
Method 1 fails because it is interpretted as a function called "this" -- it
is in quotes.
Method 2 fails because with the parentheses and not in quotes, the function
is executed immediately, and in fact could return another function as the
value to be "called".
Clear, sort of?
....Jim Lee, Dallas, TX...
 
R

Richard Cornford

Jimnbigd said:
Use the 2nd way, but leave off the parentheses:
this.interval = setInterval(this.showNext, 2000);

Which will loose the association with the object instance and so be
useless in real world examples.
Reason:
Method 1 fails because it is interpretted as a function
called "this" -- it is in quotes.
<snip>

Nothing is interpreted 'as a function called "this"', the - this -
keyword, in this context, is interpreted as a reference to the global
object, and - this.showNext - is interpreted as a property of the global
object. Because that property is not defined an error is generated when
it is called as a method.

If you are going to post answers to questions that have already been
answered twice it would be a good idea to read and understand the other
answers, and not be posting responses that are factually wrong and
disregard an important detail that has been covered in those other
answers.
"marktm" <[email protected]> wrote ...
<snip>

Please do not top-post on comp.lang.javascript, see the FAQ for details.

Richard.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top