0

I seem to be running into a bit of an issue regarding this when used in regards to namespaces in JavaScript. Specifically, whenever I call a namespace function via setTimeout or setInterval I seem to no longer be using the correct value of this.

For example, consider the following code:

var myNamespace = {
    myVar: 123,

    foo: function () {
        console.log('Inside foo');
        console.log('this.myVar = ' + this.myVar);
        console.log('myNamespace.myVar = ' + myNamespace.myVar);

        // This works excactly as expected, it prints 123 and 123
        this.bar();

        // This does not, it prints undefined and 123
        setTimeout(this.bar, 250);
    },

    bar: function () {
        console.log('Inside bar');
        console.log('this.myVar = ' + this.myVar);
        console.log('myNamespace.myVar = ' + myNamespace.myVar);
    }
}

myNamespace.foo();

When bar is called directly from foo everything works as I expect it to: it prints 123 and 123.
However, when bar is called from setTimeout, it prints undefined and 123.

It seems that the second way bar is called that the value of this isn't what I expect. I expect it to be myNamespace but it appears to be window.


That leads me to two questions:

  1. Is there a way to keep the this value inside of bar always pointing to myNamespace regardless of where it was called from?
  2. Would it be more appropriate to hard-code myNamespace. in place of this. inside of bar?
Mr. Llama
  • 20,202
  • 2
  • 62
  • 115

1 Answers1

2

Thats because this changes depending the scope, one way would be to bind an anonymous function:

setTimeout(function(){this.bar()}.bind(this), 250);
taxicala
  • 21,408
  • 7
  • 37
  • 66
  • 2
    prettified: `setTimeout(this.bar.bind(this), 250);` – KJ Price Apr 13 '15 at 17:33
  • It also appears that adding `.bind(myNamespace)` to the definition of `bar` works as well. Is there a standard on which convention is preferred? – Mr. Llama Apr 13 '15 at 17:34
  • What is with wrapping it in a function? – epascarello Apr 13 '15 at 17:35
  • You can bind the method to call to the instance as well, thats why I said `one way would be` . – taxicala Apr 13 '15 at 17:36
  • Some prefer declaring a `var _this = this` and then use `_this` all along theyr code... – taxicala Apr 13 '15 at 17:37
  • I think epascarello's point was that `this.bar.bind(this)` is equivalent and shorter. – Felix Kling Apr 13 '15 at 17:38
  • 1
    This example doesn't actually execute `bar` ever, and even if it did, the anonymous function is completely unnecessary (if you don't have `bind`, you need to capture `this` via closure, which you aren't doing). Not to mention the question is a dupe anyway. – ssube Apr 13 '15 at 17:38
  • @ssube please read the comments, The OP stated that he could also make it work binding the namespace. – taxicala Apr 13 '15 at 17:41
  • Just tested it in my console. It does work. I can clearly see the logs properly and no error thrown. – taxicala Apr 13 '15 at 17:45
  • It won't throw an error, but you'll only see the first two sets of logs (from the direct calls). If you were to use `setTimeout(function(){this.bar()}.bind(this)`, then the timeout would work as well. – ssube Apr 13 '15 at 17:48
  • True, forgot the parenthesis. – taxicala Apr 13 '15 at 17:49