Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use "setTimeout" to invoke object itself

Why can't I use setTimeout in a javascript object?

Message = function () {

    ...
    ...        

    this.messageFactory = ...
    this.feedbackTag = document.getElementById('feedbackMessages');

    this.addInfo = function (message) {
        var info = this.messageFactory.createInfo(message); // create a div
        this.feedbackTag.appendChild(info);

        setTimeout('this.feedbackTag.removeChild(info)', 5000);
        // why in here, it complain this.feedbacktag is undefined ??????

    };
}

Thanks for Steve`s Solution, now it will work if the code is as below... because the 'this' before was actually pointing to the function within setTimeOut, it cannot rearch Message.

Message = function () {

    ...
    ...        

    this.messageFactory = ...
    this.feedbackTag = document.getElementById('feedbackMessages');

    this.addInfo = function (message) {
        var info = this.messageFactory.createInfo(message); // create a div
        this.feedbackTag.appendChild(info);

        var _this = this;
        setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000);

    };
}

But why doesn`t it work if we do this:

Message = function () {

    ...
    ...        

    this.messageFactory = ...
    this.feedbackTag = document.getElementById('feedbackMessages');
    // public function
    this.addInfo = function (message) {
        var info = this.messageFactory.createInfo(message); // create a div
        this.feedbackTag.appendChild(info);

        delayRemove(info);

    };
    // private function
    function delayRemove(obj) {
        var _this = this;
        setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000);
    }
}
like image 789
jojo Avatar asked Jul 09 '09 03:07

jojo


People also ask

Can setTimeout return a value?

The setTimeout() returns a timeoutID which is a positive integer identifying the timer created as a result of calling the method. The timeoutID can be used to cancel timeout by passing it to the clearTimeout() method.

Can we make setTimeout synchronous?

You can also run setTimeout synchronously with await, promise.

Can we call function inside setTimeout?

The setTimeout() is a method inside the window object, it calls the specified function or evaluates a JavaScript expression provided as a string after a given time period for only once.


3 Answers

Try replacing this line:

setTimeout('this.feedbackTag.removeChild(info)', 5000); 

with these two lines:

var _this = this; setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000); 

Note:

Never pass setTimeout a string, as this invokes eval (which you should only use when necessary). Instead, pass setTimeout a function reference (this can be an anonymous function).

Finally, always check that the this keyword is pointing to what you think it points to (see http://www.alistapart.com/articles/getoutbindingsituations).

Addressing Question 2:

I believe that for normal functions, this is set to the window object—regardless of where they are declared. So moving the code into a separate function wouldn't fix the problem.

like image 195
Steve Harrison Avatar answered Sep 21 '22 12:09

Steve Harrison


A neater way is to just pass this as an argument to the function being called in the timeout:

function delayRemove(obj) {
  setTimeout(function(_this) {
      _this.feedbackTag.removeChild(obj);
    }, 5000, this);
}

You should really pass obj as an argument as well, just to make sure it is in scope (the number of parameters is unlimited):

function delayRemove(obj) {
  setTimeout(function(_this, removeObj) {
      _this.feedbackTag.removeChild(removeObj);
    }, 5000, this, obj);
}

HTML5 and Node.js extended the setTimeout function to accept parameters which are passed to your callback function. It has the following method signature.

setTimeout(callback, delay, [param1, param2, ...])

As setTimeout isn't actually a JavaScript feature your results may vary across browsers. I couldn't find any concrete details of support, however as I said this is in the HTML5 spec.

like image 34
Luca Spiller Avatar answered Sep 20 '22 12:09

Luca Spiller


To answer your last question: "Why doesn`t it work if we do this":

Message = function () {

...
...        

this.messageFactory = ...
this.feedbackTag = document.getElementById('feedbackMessages');
// public function
this.addInfo = function (message) {
    var info = this.messageFactory.createInfo(message); // create a div
    this.feedbackTag.appendChild(info);

    delayRemove(info);

};
// private function
function delayRemove(obj) {
    var _this = this;
    setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000);
}}

It's not working because you are passing an undefined variable (info) instead of a defined variable (obj). Here is the corrected function:

function delayRemove(obj) {
var _this = this;
setTimeout(function() { _this.feedbackTag.removeChild(obj); }, 5000);}
like image 33
ecartsiger Avatar answered Sep 19 '22 12:09

ecartsiger