4

Let's say I have a basic dumb javascript class :

var FunctionX = function(configs) {
this.funcConfigs = configs;
}

FunctionX.prototype.getData = function() {
  return $.get('/url');
}

FunctionX.prototype.show = function(promise) {
  console.log(this.funcConfigs); // <-- this here is the promise itself, I'm looking to get the instance's configs
}

FunctionX.prototype.setup = function() {
  this.GetData().then(show);
}

var f = new FunctionX({ "a": "b" });
f.setup();

Now I'm trying here in the show function to access the instance variable "funcConfig". "This" is the promise, and "funcConfigs" directly returns undefined.

I tried to resolve this issue with a .resolveWith(this) but it does not solve this issue.

How can I access the instances variables in this scope context?

user2864740
  • 60,010
  • 15
  • 145
  • 220
Erick
  • 5,969
  • 10
  • 42
  • 61
  • Nothing to do with promises, only `this` in functions invoked with different contexts. – user2864740 Dec 03 '13 at 22:19
  • See http://stackoverflow.com/questions/14561723/this-in-callback-functions , http://stackoverflow.com/questions/346015/javascript-closures-and-this-context?lq=1 , http://stackoverflow.com/questions/10120271/accessing-this-type-javascript-variables-from-other-functions?rq=1 and similar – user2864740 Dec 03 '13 at 22:21
  • I put back in the jquery-deferred tag for use of [`resolveWith`](http://api.jquery.com/deferred.resolveWith/), which tries to approach the problem from the opposite way (e.g. specifies a context, doesn't bind to an existing context). If that "does not solve the issue" then `this` is already wrong in the context `resolveWith` is used. – user2864740 Dec 03 '13 at 22:26
  • Does that code actually run? I could understand `this.getData().then(this.show);` (though you may still have the same issue). – Beetroot-Beetroot Dec 04 '13 at 05:36

1 Answers1

7

In agreement with user2864740, the issue is most likely caused because this is not what you expect it to be when show is invoked as a callback. To make this work properly, you need to capture the proper this in a closure (e.g. var that = this;), and invoke it explicitly.

In other words...

FunctionX.prototype.setup = function() {
   var that = this;

   this.getData().then(function () {
      that.show();
   });
}

EDIT: For a slightly cleaner syntax (using underscore.js):

FunctionX.prototype.setup = function() {
   var that = this;

   this.getData().then(_.bind(this.show, this));
}
jeremyalan
  • 4,658
  • 2
  • 29
  • 38
  • Yep but then it defeats completely the goal of the use of promises which is to chain to make the code cleaner. – Erick Dec 03 '13 at 22:44
  • Hmm... I'm not sure I agree with you about defeating the purpose of promises. We're still using the callback nature of promises to chain functions together, we're just chaining a new function that wraps the existing function. If it's just a matter of cleaner syntax, see my edit. – jeremyalan Dec 03 '13 at 22:55
  • 1
    Where did underscore suddenly come from? – Beetroot-Beetroot Dec 04 '13 at 05:33
  • @Beetroot-Beetroot it comes from underscorejs (http://underscorejs.org/#bind). The idea is nice but I can't use UnderscoreJS. Fortunately enough, the native js function bind was enough to solve the problem via `this.getData().then(this.show.bind(this));`. – Erick Dec 04 '13 at 13:44
  • @Beetroot-Beetroot Fair question, I prefer the original syntax, it's not worth pulling in underscore.js just for this purpose, but useful if you're already using it for other things. – jeremyalan Dec 04 '13 at 16:19
  • @Erick The native .bind function achieves the same result, but beware of browser compatibility. In particular, it looks like this function only works in IE9+, similar support issues on all other modern browsers. This may be fine, just wanted to point it out. – jeremyalan Dec 04 '13 at 16:21