0

I'm new to JS and especially to prototypes. I have this class and I cannot figure out how to access the properties.

var Lobby = function (preloader, serverConn) {
  // Hold a reference to EventBus
  this.serverConn = serverConn;
  this.preloader = preloader;

  this.scheduleItemService = new ScheduledItemService(this.preloader);
  this.stage = new createjs.Stage("lobbyCanvas");
};

Lobby.prototype.start = function(me, signedRequest) {
    sendMessage(data, function() {
       // inside this scope this.stage is undefined!
       renderLobbyImages(this.stage, this.scheduleItemService);
    });
};

function renderLobbyImages(stage, scheduleItemService) {
  stage.update();
};

Calling code:

var lobby = new Lobby(preloader, serverConn);
lobby.start(me, status.authResponse.signedRequest);

What am I doing wrong accessing 'renderLobbyImages' ??

Thank you :-)

8
  • 5
    Are you getting any errors..? What is wrong..? Commented Dec 22, 2015 at 17:21
  • 1
    How are you calling start()? Commented Dec 22, 2015 at 17:25
  • 2
    Please show us how you're using the constructor, and how you're calling .start. Commented Dec 22, 2015 at 17:26
  • You had working code and no problem description initially (which means there was no problem) and then you updated the question with non-working code... @__@ Commented Dec 22, 2015 at 17:29
  • I added how I run this code. Commented Dec 22, 2015 at 17:32

2 Answers 2

4

In javascript, this is not resolved based on where it is declared/used. It is resolved when it gets called. (see: How does the "this" keyword in Javascript act within an object literal?).

Therefore, in the code above, since this is called in the callback to sendMessage(), and since sendMessage is asynchronous (meaning the callback will be called long after the call to start() have returned), this is therefore referring to the global object (which is window in web browsers, something unnamed in node.js).

So effectively, your code is doing this (no pun intended):

sendMessage(data, function() {
   renderLobbyImages(stage, scheduleItemService);
});

Since there are no global variables called stage or scheduleItemService both are effectively undefined!

Fortunately, there is a workaround for this. You can capture the correct object in a closure:

var foo = this;
sendMessage(data, function() {
   renderLobbyImages(foo.stage, foo.scheduleItemService);
});

Alternatively, you can pass the correct object (this) into an IIFE:

(function(x){
    sendMessage(data, function() {
        renderLobbyImages(x.stage, x.scheduleItemService);
    });
})(this); // <-------- this is how we pass this

or:

sendMessage(data, (function(a){
    return function(){
        renderLobbyImages(a.stage, a.scheduleItemService);
    }
})(this));

Or in this case, since stage and scheduleItemService are not functions, you can even pass them directly:

sendMessage(data, (function(a,b){
    return function(){
        renderLobbyImages(a,b);
    }
})(this.stage, this.scheduleItemService));

There are lots of solutions to this problem. Just use the one you're most comfortable with.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot - You certainly nailed it!
0

Two problems.

  1. this is missing in your constructor function on scheduleItemService.

  2. Some functions you call to assign values seem to be not returning anything.

     new createjs.Stage("lobbyCanvas");
     new ScheduledItemService
    

Your calling method is alright.

this always refers to the calling object. When you say...

varlobby = new Lobby();
lobby.start();

... your calling object is lobby which has all the fields the start() function needs. But there initialization seems to be not working properly.

Please read this MDN starter guide.

Also we are having a some discussion about classical and prototype based OOP in this question. Please see the answer of Paul S for more about the tutorial I mentioned. Please see my answer if you need to see the tutorial in classical OOP light.

2 Comments

Your constructor function is ok. And you are calling it correctly. The only possibility is that createjs.Stage and ScheduledItemService don't create the properties as expected. So, they are 'undefined'. Please set a breakpoint there and see in the console if these functions work properly.
I know what's the problem but I don't know how to solve it. if I call the method directly from the .start() method than everything is defined. BUT if I call the method within an inner function of the 'sendMessage' method - then it is undefined!

Your Answer

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.