3

The code below prints out:

timedout false undefined

I.e. this is no longer refering to theActivityTimer in method timedOut(). I was wondering why this was.

var theActivityTimer = {
    timer: "",          
    active: false,       

    refresh: function () {
        theActivityTimer.timer = setTimeout(
            this.timedOut,
            5000     
        );
    },

    timedOut: function(){
        alert("timedout " +
            theActivityTimer.active + " " + this.active);
    }
}

theActivityTimer.refresh();

http://jsfiddle.net/spiderplant0/nQ4XX/

And is there a way to tell get it to work with this

3
  • It doesn't lose connection with the object; it never had a connection in the first place. The only thing that matters for the value of this is how a function is invoked. Commented Sep 4, 2013 at 17:30
  • thanks @pointy, could you elaborate please (as this doesnt really explain anything) Commented Sep 4, 2013 at 17:31
  • Unlike languages like C++, Java, C#, etc, declaring a function as "part of" an object doesn't actually result in there being any strong relationship between the function and the object. Such a function in JavaScript is just like any other function, and the only relationship involving the object is from the object to the function, as a property value. Commented Sep 4, 2013 at 17:36

3 Answers 3

3

this is based on how the method is invoked.

foo.bar(); // this === foo

var bar = foo.bar();
bar() // this === window (defaults to global object)

So setTimeout effectively does the latter.

Instead, it's common to pass an anonymous function that maintains the proper call to your instance method. Just remember that the anonymous function will also lose this, so you need to save what this is to a local variable, which is also common.

var self = this;
theActivityTimer.timer = setTimeout(function() {
    self.timedOut()
}, 5000);

There are other ways to manipulate context (the value of this), but this one is probably the easiest to understand and the most widely supported.

Sign up to request clarification or add additional context in comments.

2 Comments

-1 I'm putting my foot down on this. I appreciate the "easiness" of this answer, but you're doing no favors in terms of teaching actual good practices. Having context variables floating around your scripts is a recipe for complete disaster. I know fn.bind is newer, but fn.call and fn.apply are very widely supported.
Thanks very much, as its a object literlal initialiser I used: function(){theActivityTimer.timedOut();},
3

This question is asked all the time; You'll want to use fn.bind

var theActivityTimer = {
    timer: null,          
    active: false,       

    refresh: function () {
        this.timer = setTimeout(this.timedOut.bind(this), 5000);
    },

    timedOut: function(){
        alert("timedout " + this.active);
    }
};

From the fn.bind docs

Creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.


Disclaimer:

fn.bind was implemented in ECMAScript 5. If you're using this in a browser and need to support older versions, check out es5-shim


3 Comments

why this.timeout.call(this) ? when you can do exactly the same thing with this.timeout()? two codes are always identical. And here that is a problem since 'this' is not available
in your alternative code, var self = this, or var that = this is actually necessary.
Thanks v much for the explanation (I need IE8 compatibility though so went with other answer)
0

I want to add another solution to this thread to add inline solution that does not need any extra work or library and is cross-browser.

var theActivityTimer = {
    timer: "",          
    active: false,       

    refresh: function () {
         theActivityTimer.timer = setTimeout(function() {
             theActivityTimer.timedOut();
         }, 5000);
    },

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.