This question already has answers here:
JavaScript setInterval and `this` solution
(9 answers)
Closed 8 years ago.
I'm trying to call my method Move(); inside the object MySnake using setInterval:
function Snake()
{
this.Start = function(Speed)
{
this.Movement = setInterval(function(){
this.Move();
},Speed);
}
}
var MySnake = new Snake();
MySnake.Start(400); //Doesn't work
and this isn't working. But when I call the method through the instance 'MySnake':
function Snake()
{
MySnake.Start = function(Speed)
{
this.Movement = setInterval(function(){
MySnake.Move();
},Speed);
}
}
var MySnake = new Snake();
MySnake.Start(400); //Works
I wan't the one whit 'this' keyword to work
This is because this is defined by the caller in JavaScript. The easiest solution is to store it in another variable:
function Snake()
{
this.Start = function(Speed)
{
var that = this;
this.Movement = setInterval(function(){
that.Move();
},Speed);
}
}
var MySnake = new Snake();
MySnake.Start(400); //Work
Here is a working jsfiddle. In your example, the inner this is the global window.
Another solution would be to bind this in the function to the local this, as shown in this second jsfiddle:
function Snake()
{
this.Move = function() { document.body.innerHTML += '.'; };
this.Start = function(Speed)
{
this.Movement = setInterval((function(){
this.Move();
}).bind(this),Speed);
}
}
var MySnake = new Snake();
MySnake.Start(400); //Work
But this one is harder to read.
when you do this.move(); "this" is inside anonymous function passed into the setInterval method, hence you will get an error.
function Snake()
{
this.Start = function(Speed)
{
var _this = this;
this.Movement = setInterval(function(){
_this.Move();
},Speed);
}
}
var MySnake = new Snake();
MySnake.Start(400)
This will work since the reference to the object is captured by closure created by the callback for setInterval.
Related
I got these variables
var moneycount = 0;
var b1 = document.createElement("IMG");
function update() {
document.getElementById('money').innerHTML = moneycount;
}
And functions for saving/loading
function save() {
localStorage.setItem("moneycount", moneycount);
};
function load() {
moneycount = localStorage.getItem("moneycount");
moneycount = parseInt(moneycount);
update();
};
This function works as intended but wont update with localStorage
function add() {
moneycount = moneycount + 1
if (moneycount >= 1) {
document.getElementById('badge1').appendChild(b1);
}
update();
}
It seems like var moneycount = 0 still is 0 after I load localStorage because if (moneycount >= 1) is not working. The document element is still displaying a bigger number after loading localStorage. Any ideas on how I can store my add() function?
Edit:
Found a temporary solution with setting setInterval(save, 5000); and adding <body onload="load();"> and calling it on refresh.
that is because you do not update the localStorage instead you just update the html element: should do it as followed:
var moneycount = 0;
var b1 = document.createElement("IMG");
function update() {
document.getElementById('money').innerHTML = moneycount;
localStorage.setItem("moneycount", moneycount);
}
function save() {
localStorage.setItem("moneycount", moneycount);
};
function add() {
localStorage.getItem("moneycount")+= 1;
if (moneycount >= 1) {
document.getElementById('badge1').appendChild(b1);
}
update();
}
The reason is (like mentioned in the comments) that your load() function also saves the localStorage instead of retrieving the value.
Your load() function should look like this:
function load() {
moneycount = localStorage.getItem("moneycount");
update();
};
This question already has answers here:
JavaScript setInterval and `this` solution
(9 answers)
Closed 7 years ago.
When I try and run the add function it gives TypeError: this.add is not a function
function Timer(){
this.t;
this.count = 0;
this.start = function(){
this.t = setInterval(function () {this.add()}, 1000);
}
this.add = function(){
this.count++;
console.log(this.count);
}
}
function startTimer(){
timer = new Timer();
timer.start();
}
How am I able to access this.add function in that instance?
A solution would be to create a variable to hold this but a simpler one is to use bind:
this.t = setInterval(this.add.bind(this), 1000);
This happens because this inside your anonymous function get wrong context. You need to bind that function to your original context:
this.t = setInterval(function () {this.add()}.bind(this), 1000);
Or keep reference to your context inside some variable:
function Timer(){
this.t;
this.count = 0;
this.start = function(){
var self = this;
this.t = setInterval(function () {self.add()}, 1000);
}
...
It's the first time i use objects with JavaScript, i used the method 1.1 from this tutorial, i have this code:
function MyClass() {
this.currentTime = 0;
this.start = function() {
this.currentTime = new Date().getTime();
console.log(this.currentTime); //this line prints the time i just set
this.intervalID = setInterval(this.step, 25);
};
this.step = function() {
var d = new Date().getTime();
console.log(this.currentTime); //always prints "undefined" to the console
};
this.stop = function() {
clearInterval(this.intervalID);
};
}
The problem is that in the step() function, console.log(this.currentTime)always prints "undefined", while this.currentTime was set in the start() function.
Why? What am i missing?
You are using the scope of the function this.fn in each case, that's why you're not adding it to the MyClass's scope. You have to store the this object and use it to add properties.
function MyClass() {
this.currentTime = 0;
var self = this;
this.start = function() {
self.currentTime = new Date().getTime();
console.log(self.currentTime); //this line prints the time i just set
self.intervalID = setInterval(self.step, 25);
};
this.step = function() {
var d = new Date().getTime();
console.log(self.currentTime); //always prints "undefined" to the console
};
this.stop = function() {
clearInterval(self.intervalID);
};
}
I'm trying to run the following code, but get an error in the gameLoop function saying: JavaScript runtime error: Object doesn't support property or method 'update'.
I'm a beginning JavaScript programmer. Can you spot what is wrong with this code?
function Core(context) {
this.context = context;
this.fps = 500;
this.sprite = new Sprite();
}
Core.prototype.run = function() {
setInterval(this.gameLoop, this.fps); // <<<< PROBLEM
}
Core.prototype.gameLoop = function () {
this.update();
this.draw();
}
Core.prototype.update = function () {
this.sprite.x += 50;
this.sprite.y += 50;
}
Core.prototype.draw = function () {
this.context.clearRect(0, 0, 300, 300);
this.context.fillRect(this.sprite.x, this.sprite.y, 50, 50);
this.context.fillText('x: ' + this.sprite.x + ' y: ' + this.sprite.y, 10, 250);
}
In JavaScript, this is defined entirely by how a function is called, not where or how it's defined. The problem is that setInterval doesn't call your code with the correct this value. To fix:
function Core(context) {
var self = this;
this.context = context;
this.fps = 500;
this.sprite = new Sprite();
this.boundGameLoop = function() {
self.gameLoop();
};
}
Core.prototype.run = function() {
setInterval(this.boundGameLoop, this.fps);
}
On JavaScript engines that have ES5 features (or if you're using an ES5 "shim"), you can change Core to:
function Core(context) {
this.context = context;
this.fps = 500;
this.sprite = new Sprite();
this.boundGameLoop = this.gameLoop.bind(this);
}
More reading:
Mythical methods
You must remember this
Function#bind in the ES5 spec
Side note: Your code relies on the horror that is Automatic Semicolon Insertion. (All of your function assignments — Core.prototype.run = function() { ... }) need semicolons after the closing }.)
What you need is .bind.
setInterval(this.gameLoop.bind(this), this.fps)
Try reshuffling your code so that you declare update before you call it, e.g.
Core.prototype.update = function () {
this.sprite.x += 50;
this.sprite.y += 50;
}
Core.prototype.gameLoop = function () {
this.update();
this.draw();
}
Game.prototype.run = function() {
window.setInterval(function() {
var thisLoop = new Date().getTime();
this.update();
this.render();
lastLoop = thisLoop;
}, 1000 / this.fps);
};
game.js:198Uncaught TypeError: Object [object DOMWindow] has no method 'update'
Why is this happening ?
"this" should relate to the Game object.
Cache the this variable, or use Function.bind:
Game.prototype.run = function() {
var _this = this;
window.setInterval(function() {
var thisLoop = new Date().getTime();
_this.update();
_this.render();
lastLoop = thisLoop;
}, 1000 / this.fps);
};
Or, using Function.bind:
Game.prototype.run = function() {
window.setInterval((function() {
...
}.bind(this), 1000 / this.fps);
};
this in a function passed to setInterval refers to the global window object, or is undefined (in strict mode).
Another method, similar to the first one. Pass this as a parameter to the function (so that no extra local variable is used):
Game.prototype.run = function() {
window.setInterval(function(_this) {
var thisLoop = new Date().getTime();
_this.update();
_this.render();
lastLoop = thisLoop;
}, 1000 / this.fps, this);
};
No, this in the scope of the function refers to the function itself. Its somewhat hard to wrap your head around scoping in JS if you're not used to it.
The easy solution is to cache the context of "this" outside the anonymous function and use that instead.
Game.prototype.run = function() {
var game = this;
window.setInterval(function() {
var thisLoop = new Date().getTime();
game.update();
game.render();
lastLoop = thisLoop;
}, 1000 / this.fps);
};
DEMO: http://jsfiddle.net/kmendes/awzMn/
In this case there's no way you can do that because the setInterval function has a different scope. This is what you can do:
Game.prototype.run = function() {
var currentGame = this;
window.setInterval(function() {
var thisLoop = new Date().getTime();
currentGame.update();
currentGame.render();
lastLoop = thisLoop;
}, 1000 / this.fps);
};
Try this :
Game.prototype.run = function() {
var intervalCallBack = function() {
var thisLoop = new Date().getTime();
this.update();
this.render();
lastLoop = thisLoop;
};
var self = this;
window.setInterval(function(){intervalCallBack.call(self);}, 1000 / this.fps);
};
Because of the fact that setInterval and setTimeout executes your callback in the global context, your this "pointer" that you used to refer to your game object is now referring to the global object (window) , which of course has no method 'update'.