Object doesn't support method - javascript

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();
}

Related

Function not defined using setTimeout

For some reason after I wrapped my js code in an immediately invoked function expression I'm getting progressBar not defined. Wondering why this is the case?
(function(){
"use strict"
var progressBar = function(){
var bar = document.getElementById('pbar'),
status = document.getElementById('status'),
barValue = bar.value;
status.innerHTML = barValue + "%";
bar.value++;
var increment = setTimeout("progressBar()", 50);
if(bar.value == 100){
status.innerHTML = '100% - Straight Besting';
bar.value = '100';
clearTimeout(increment);
}
}
progressBar();
})()
When you pass a string to setTimeout, it is invoked in the context of the global window object.
Change the setTimeout line to:
var increment = setTimeout(progressBar, 50);
E.g.
(function() {
let i = 0;
let myfunction = function() {
console.log(i++);
if (i < 10) setTimeout(myfunction, 100);
};
myfunction();
})()

Javascript binding issue not resolved by calling bind

I am trying to recursively call a function until the game has ended, however, during the execution "this" gets reset to 'window', which causes the following error: "cannot read property 'step' of undefined."
I have tried rewriting the offending line as
this.game.bind(this).step();
as well as
this.game.step.bind(this);
Neither are working. For context, step is just a function that calls two helpers in Game that move objects and look for collisions, when I used those instead of step, the error remained.
/* globals key */
const Game = require('./game.js');
let speed = 1;
function GameView(ctx) {
this.ctx = ctx;
this.game = new Game();
}
GameView.prototype.start = function (callback) {
// let that = this
this.bindKeyHandlers();
this.animate(0);
};
GameView.prototype.animate = function(time) {
speed += 1;
if (speed >= 605) {
speed = 0;
};
this.game.step();
this.game.draw(this.ctx, speed);
if(!this.game.lose()){
requestAnimationFrame(this.animate());
}
else {
this.ctx.fillStyle = "white";
this.ctx.font = "italic "+24+"pt Arial ";
this.ctx.fillText(`Game Over \n Press Enter to restart`, 100,200 );
key('enter', ()=>{
this.game = new Game();
this.start();
});
}
};
GameView.prototype.bindKeyHandlers = function() {
key('d', () => {
this.game.ship.power([2, 0]);
});
key('a', () => {
this.game.ship.power([-2, 0]);
});
key('s', () => {
this.game.ship.power([0, 2]);
});
key('w', () => {
this.game.ship.power([0, -2]);
});
key('l', () => {
this.game.ship.fireBullet();
});
};
module.exports = GameView;
Your problem is that this of the animate function does not refer to the context you wish it to. So your offending line (or lack thereof) is completely elsewhere.
Function.bind returns a function and you need to this new bound functions somewhere and the perfect place for this is the constructor. Here's an example:
function GameView(ctx) {
this.ctx = ctx;
this.game = new Game();
this.animate = this.animate.bind(this)
}
See this jsfiddle for more, remember to open your developer console to witness the error from calling notBound
Hope this helps!

Javascript / Jquery OOP not inheriting attributes

I have created a Constructor class / function that has 4 methods and a 5 attributes. The problem is when i create a new instance of the constructor it doesn't inherit the first attribute (this.el = element) which is 'affiliateSection' on the new instance called: animation1. Thanks in advance..
// main class
function AnimateImages(el, time, effect, setTime, h){
this.el = element; // this is not inheriting from 'animate1'
this.time = time;
this.effect = effect;
this.setTime = setTime;
this.h = height;
this.delayAnimate = function() {
this.element.delay(time)
.queue(function(next) {
$(this).addClass(effect);
next();
});
};
// function for multi animations
var multiAnimations = function() {
var i = 0;
this.element.each(function (key, value) {
i = i + setTime;
var tthis = this;
delayAnimate($(this), i, tthis.effect);
});
};
// load on window height
var onWindowAnimate = function () {
if ($(this).scrollTop() > this.height) {
// call multi animations function
var tthis = this;
multiAnimations(this.element, tthis.setTime, tthis.effect);
}
};
// hide function
var hideAnimatedEl = function (){
this.element.each(function(){
$(this).css("visibility", "hidden");
});
};
} // End of AnimateImages
/*============================================================*/
var affiliateSection = $("#aff-img > li > img");
// new instance of AnimateImages
var animation1 = new AnimateImages(affiliateSection, 200, 'subtlefadeIn',
300, 50);
$(window).scroll(function () {
setTimeout(function(){
animation1.onWindowAnimate();
}, 1000);
});
It looks like you have your member variable initializations backwards. Try this:
this.element = el; // this is not inheriting from 'animate1'
this.time = time;
this.effect = effect;
this.setTime = setTime;
this.height = h;
Your parameter name is wrong:
this.el = element;
element is not in the parameter list.
Since you are reffering to this.element inside your function, I am assuming that your first line should be
this.element = el;

Can't call a method by using 'this' [duplicate]

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.

javascript setInterval on an object's function only calls 2x

var focus = true;
function z() {
this.t = 0;
this.p = function (t) {
if (focus == true) {
this.t = t;
alert(this.t);
}
}
}
var zp = new z();
setTimeout('zp.p(0)', 100);
window.setInterval('zp.p(1)', 2000);
var ftimer = setTimeout('focus=false', 2000);
document.addEventListener('mousemove', function (e) {
clearTimeout(ftimer);
focus = true;
ftimer = setTimeout('focus=false', 2000);
}, false);
I have this code. but for some reason it only alerts twice even with continuous mouse movements. I have been working at this and investigating in firebug and focus is true when I am moving my mouse. I have been trying to figure out what is going on.. even if I do this:
function z() {
this.t = 0;
this.p = function (t) {
if (focus == true) {
this.t = t;
}
alert(this.t);
}
}
It still only alerts twice.
I have tried using a looping setTimeout function too but that doesnt work either. It is driving me crazy.
Good that you found your bug.
I would write your code using a bit more functions-as-first-class-objects and less eval logic:
var focus = true;
function z() {
var that = this; // we won't always have the correct value of "this"
this.focus = true;
this.t = 0;
this.p = function (t) {
if (that.focus == true) {
that.t = t;
alert(t);
}
}
this.fade = ( function(obj){ return function(){ obj.focus = false; } } )(this); // Using self-invokation
}
var zp = new z();
setTimeout(zp.p, 100, 0);
window.setInterval(zp.p, 2000, 1);
var ftimer = setTimeout(zp.fade, 2000);
document.addEventListener('mousemove', function (e) {
clearTimeout(ftimer);
zp.focus = true;
ftimer = setTimeout(zp.fade, 2000);
}, false);
I used a self-invoking function on line 10: ( function(obj){ return function(){...} })(this);, and set this to a different variable.
I found out that it was just related to firefox and that firefox choked on a line of code so that is why it wouldn't run. So I fixed that and now everything is all good.

Categories