I need to access this
from my setInterval
handler
prefs: null,
startup : function()
{
// init prefs
...
The setInterval line should look like this:-
this.intervalID = setInterval(
(function(self) { //Self-executing func which takes 'this' as self
return function() { //Return a function in the context of 'self'
self.retrieve_rate(); //Thing you wanted to run as non-window 'this'
}
})(this),
this.INTERVAL //normal interval, 'this' scope not impacted here.
);
Edit: The same principle applies to the " onload
". In this case its common for the "outer" code to do little, it just sets up the request an then sends it. In this case the extra overhead an additinal function as in the above code is unnecessary. Your retrieve_rate should look more like this:-
retrieve_rate : function()
{
var self = this;
var ajax = new XMLHttpRequest();
ajax.open('GET', 'http://xyz.com', true);
ajax.onreadystatechanged= function()
{
if (ajax.readyState == 4 && ajax.status == 200)
{
// prefs available as self.prefs
}
}
ajax.send(null);
}
window.setInterval(function(){console.log(this)}.bind(this), 100)
this is legal in javascript and saves lots of code :)
prefs: null,
startup : function()
{
// init prefs
...
this.retrieve_rate();
var context = this;
this.intervalID = setInterval(function()
{
context.retrieve_rate();
}, this.INTERVAL);
},
retrieve_rate : function()
{
var ajax = null;
ajax = new XMLHttpRequest();
ajax.open('GET', 'http://xyz.com', true);
var context = this;
ajax.onload = function()
{
// access prefs using context.
// e.g. context.prefs
}
}
The default behavior of setInterval
is to bind to the global context. You can call a member function by saving a copy of the current context. Inside retrieve_rate the this
variable will be correctly bound to the original context. Here is what your code would look like:
var self = this;
this.intervalID = setInterval(
function() { self.retrieve_rate(); },
this.INTERVAL);
Bonus tip: For a plain function reference (as opposed to an object reference which has a member function) you can change the context by using JavaScript's call
or apply
methods.
With modern browsers the setInterval method allows additional parameters which are passed through to the function specified by func once the timer expires.
var intervalID = scope.setInterval(func, delay[, param1, param2, ...]);
Hence, a possible solution can be:
this.intervalID = setInterval(function (self) {
self.retrieve_rate();
}, this.INTERVAL, this);
A demo:
var timerId;
document.querySelector('#clickMe').addEventListener('click', function(e) {
timerId = setInterval(function (self) {
self.textContent = self.textContent.slice(0, -1);
if (self.textContent.length == 0) {
clearInterval(timerId);
self.textContent = 'end..';
}
}, 250, this);
})
<button id="clickMe">ClickMe</button>
With improving browser support the time is now good to use the EcmaScript 6 enhancement, the arrow => method, to preserve this
properly.
startup : function()
{
// init prefs
...
this.retrieve_rate();
this.intervalID = setInterval( () => this.retrieve_rate(), this.INTERVAL);
},
Using => method preserves the this
when retrieve_rate()
is called by the interval. No need for funky self or passing this
in parameters