简体   繁体   中英

JS prototype class not all properties are accessible

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 :-)

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 .

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM