Object undefined?

Hello Coders,

I am fairly new to JavaScript development and am working to get my first
2D side scroller up and running with some basic physics.

See below for sample code; you must really only pay attention to the top 3 declarations. I have successfully made keyPressed and keyReleased event listener functions, but this.pressedKeys always comes up as undefined.

In my pressedKeys Object, I am trying to map numbers to boolean values, indicating whether or not the arrow keys are being pressed or not.

What am I missing in my syntax here?

Thanks in advance!

function Dude(x,y,h,m,maxspd,boxes){

	this.pressedKeys = {
		37 : false,
		38 : false,
		39 : false
	}

	this.keyPressed = function(evt){
		console.log(this.pressedKeys);
		this.pressedKeys[evt.which] = true;
	}
	this.keyReleased = function(evt){
		this.pressedKeys[evt.which] = false;
	}

	/*
	Coordinate + drawing vars
	*/
	this.x = x;
	this.y = y;
	this.h = h;
	this.w = 2*this.h/5;
	this.canvas = document.getElementById("dude");
	this.ctx = this.canvas.getContext("2d");
	this.wandColor = "#804000";
	this.wandTipColor = "#FFFF00";

	/*
	Physics vars
	*/
	this.mass = m;
	this.vel = [0,0]; //x,y
	this.acc = [0,0];
	this.pos = [this.x + (this.w/2), this.y + (this.h/2)]; //x,y
	this.maxspd = maxspd;
	
	

	/*
	Keypoint mapping vars
	*/
	this.lFoot = [this.x+(5*this.w/16),this.y+(this.h*0.85)];
	this.rFoot = [this.x+(11*this.w/16),this.y+(this.h*0.85)];
	this.groin = [this.x+(this.w/2),this.y+(this.h*0.6)];
	this.torso = [this.x+(this.w/2),this.y+(this.h*0.4)];
	this.lElbow = [this.x+(this.w/4),this.y+(this.h*(16/30))];
	this.lHand = [this.x+(this.w/8),this.y+(this.h*(19/30))];
	this.rElbow = [this.x+(this.w*3/4),this.y+(this.h*(11/30))];
	this.rHand = [this.x+(this.w*7/8),this.y+(this.h*0.3)];
	this.wand = [this.x+(this.w*9/8),this.y+(this.h*0.2)];
	this.wandTip = [this.x+(this.w*19/16),this.y+(this.h*(5/30))];
	this.neck = [this.x+(this.w/2),this.y+(this.h*0.3)];
	this.head = [this.x+(this.w/2),this.y+(this.h*0.15)];
	this.headR = 12;

	/*
		???
	*/
	this.w = this.wandTip[0] - this.x;
	this.h = this.rFoot[1] - this.y;
	this.box = new BoundingBox(this.x,this.y,this.w,this.h,boxes);

	window.addEventListener("keydown",this.keyPressed,false);
	window.addEventListener("keyup",this.keyReleased,false);

	/*
	Draws this Dude based off it's current position.
	*/
	this.draw = function() {
		this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);
		//lower body
		this.ctx.beginPath();
		this.ctx.moveTo(this.lFoot[0],this.lFoot[1]);
		this.ctx.lineTo(this.groin[0],this.groin[1]);
		this.ctx.lineTo(this.rFoot[0],this.rFoot[1]);
		this.ctx.stroke();
		//upper body
		this.ctx.beginPath();
		this.ctx.moveTo(this.groin[0],this.groin[1]);
		this.ctx.lineTo(this.torso[0],this.torso[1]);
		this.ctx.moveTo(this.lHand[0],this.lHand[1]);
		this.ctx.lineTo(this.lElbow[0],this.lElbow[1]);
		this.ctx.lineTo(this.torso[0],this.torso[1]);
		this.ctx.lineTo(this.rElbow[0],this.rElbow[1]);
		this.ctx.lineTo(this.rHand[0],this.rHand[1]);
		this.ctx.stroke();
		//wand rod
		this.ctx.beginPath();
		this.ctx.strokeStyle = this.wandColor;
		this.ctx.lineWidth = 2;
		this.ctx.moveTo(this.rHand[0],this.rHand[1]);
		this.ctx.lineTo(this.wand[0],this.wand[1]);
		this.ctx.stroke();
		//wand tip	
		this.ctx.beginPath();
		this.ctx.strokeStyle = this.wandTipColor;
		this.ctx.moveTo(this.wand[0],this.wand[1]);
		this.ctx.lineTo(this.wandTip[0],this.wandTip[1]);
		this.ctx.stroke();
		//neck & head
		this.ctx.beginPath();
		this.ctx.lineWidth = 1;
		this.ctx.strokeStyle = "#000000";
		this.ctx.moveTo(this.torso[0],this.torso[1]);
		this.ctx.lineTo(this.neck[0],this.neck[1]);
		this.ctx.arc(this.head[0],this.head[1],this.headR,Math.PI/2,-3*Math.PI/2);
		this.ctx.stroke();

		ctx.drawImage(this.canvas,0, 0);
		ctx.stroke();
	}

	this.update = function(fnet,del) {
		this.acc[0] = fnet[0]/this.m;
		this.acc[1] = fnet[1]/this.m;
		this.vel[0] = this.vel[0] + (this.acc[0]*del);
		if (Math.abs(this.vel[0]) > maxspd){
			if (this.vel[0] < 0) this.vel[0] = -maxspd;
			else this.vel[0] = maxspd;
		}
		this.vel[1] += (this.acc[1]*del);
		this.x += (this.vel[0]*del);
		this.y += (this.vel[1]*del);
	}
}

Figured it out.

Not sure why, but as soon as I moved the Object declaration to a global context outside the constructor, it worked seamlessly. Could anyone explain this?

Sure, I can give it a little try: when you are inside the this.keyPressed function, try doing a console.log(JSON.stringify(this) ) there - I think you will find that what this is has changed on you. When you define this.pressedKeys, you were in the context of your class definition itself. But when you call console.log(this.pressedKeys) inside the this.keyPressed function, the context has changed. Remember, functions create their own variable namespace, and this refers to the variable namespace itself.

So in the first, with this.pressedKeys, you’re in the variable scope of your object - but in the second, within the this.keyPressed, you’re in the variale scope of that particular function.

That right there is why React has you bind functions. In essence, doing this.keyPressed = this.keyPressed.bind(this); inside your class definition will force it to use the object’s variable namespace, rather than creating one of its own.