1

I have defined a prototype class with few properties and methods and for some reason I cannot access all the properties in some cases (mainly when callbacks are involved).

Here is my code (removed some lines to make it clearer)

var Lobby = function (preloader, serverConn) {
 // Hold a reference to EventBus
 this.serverConn = serverConn;
 this.preloader = preloader;
 this.session_id = null;
 this.scheduleItemService = new ScheduledItemService(this.preloader);
 // Instantiate lobby stage
 this.stage = new createjs.Stage("lobbyCanvas");
};
Lobby.prototype._renderLobbyImages = function(stage, scheduleItemService) {
 // at this point, 'stage' and 'scheduleItemService' are valid!
 ..
 // onScheduledItemClick callback function
 this.scheduleItemService.render(stage, this._onScheduledItemClick);
}
Lobby.prototype._onScheduledItemClick = function(event) {
 (function(inst) {
 inst.serverConn.asyncSend(
 'game.lobby',
 { 'action' : 'claim_scheduled_item',
 'session_id' : inst.session_id, **//Here, 'inst.session_id' is DEFINED!**
 },
 function (error, reply) {
 **// Here, both 'stage' and 'scheduleItemService' are UNDEFINED! WHY?!?!**
 inst.scheduleItemService.startCountdown(inst.stage);
 }
 });
 })(this);
}
ScheduledItemService.prototype.render = function(stage, onScheduledItemClick) {
 var scheduled_item = new createjs.Bitmap(preloader.getResult("scheduled_item_img"));
..
..
 scheduled_item.addEventListener('click', onScheduledItemClick);
..
}

Why this.session_id is defined in 'this' while 'stage' and 'scheduleItemService' are not defined?? these 3 are properties of Lobby class...

I tried browsing in 'this' pointer and I really couldn't find 'stage' nor 'scheduleItemService'.

I'm missing something, right?

Thank you :-)

asked Dec 23, 2015 at 16:00
2
  • Where's the prototype here? Commented Dec 23, 2015 at 16:01
  • why no this on those? i thinks you need to use "this.stage" and "this.scheduleItemService", since "this.session_id" works. Commented Dec 23, 2015 at 16:04

2 Answers 2

1

Your scheduleItemService variable is out of scope here

function (error, reply) {
 scheduleItemService.startCountdown(stage);
}

The thing is even if you did not use Promises, this code would still fail. If you want to define the renderLobbyImages and onScheduledItemClick as prototype methods, you'd have to write

Lobby.prototype.renderLobbyImages = function(){
 // this refers to a Lobby instance
 this.scheduleItemService.render(stage, this.onScheduledItemClick);
}
Lobby.prototype.onScheduledItemClick = function(){
 // this refers to a lobby instance
}

You must also use the use this keyword in the onScheduledItemClick.

Then, inside the promise callback you defined, the "this" keyword does not point back to the instance. That's why you are getting errors with your code. Inside this callback, the this changes.

To fix this, before the callback, store a temporary variable to the "this, here I named it scope". You can use this scope the same way you use this.

Lobby.prototype.onScheduledItemClick = function(event) {
 // this refers to a lobby instance
 var scope = this;
 this.serverConn.asyncSend(
 'game.lobby',
 { 
 'action' : 'claim_scheduled_item',
 'session_id' : scope.session_id.bind(scope), // Here scope instead of this. But you could use this as not inside callback. I used scope just for consistency
 },
 function (error, reply) {
 // this does NOT refer to a lobby instance. You must use scope
 scope.scheduleItemService.startCountdown(stage);
 }
});

Edit 1

After your code edit, I can still see some errors.

I see that in your Lobby.prototype._onScheduledItemClick, you are using a (inst) variable, this.serverConn.asyncSend, it should be inst.serverConn.asyncSen

--

Edit 2

Another problem with your code is the callback. The scope is not passed along. You have to "bind" your callback with a scope. This is used using function.bind();

So now, your line looks like :

this.scheduleItemService.render(stage, this._onScheduledItemClick.bind(this));

This will make it so that when your callback is called, the "this" variable will have the value of the argument you pass in bind.

answered Dec 23, 2015 at 16:12
Sign up to request clarification or add additional context in comments.

16 Comments

if all that's the case, then why would this.session_id work in the first function?
I think it's because the method was called with either apply/call/bind.
(i think OP simply forget to type this. in the 2nd function...)
The secret lies in the scheduleItemService.render method :)
The thing is the this in both methods can refer to anything. If the OP wants to use this, the methods should either be on the prototype or the constructor. Otherwise, they must always be called with bind/call/apply, or affect the global. Or it's an error.
|
0

Firstly, you aren't prefixing your things with this. Unlike some other languages, this is not optional in JavaScript.

When you enter a new function call, this is redefined. You'll want to save a reference to it.

this is defined as the parent of the called function. Therefore it changes each time a function is called. Here's what people often do:

Something.prototype.foo = function() {
 var self = this;
 doSomething(function() {
 // now this has changed, but self still references the original this
 });
};
answered Dec 23, 2015 at 16:05

1 Comment

@dandavis Therein lies a second problem. this is not optional in JavaScript.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.