2

I ran into a problem with my javascript code.

I have a class MyClass and added function myFunction to its prototype.

MyClass.prototype.myFunction = function(file){
    if(some condition){
       fs.exists("./" + file, function(exists){
           if(exists)
               console.log(this.someValue);
               /* lot of other code */
           else
               /* do something else */
    });
    }else{
        /* do something */
    }
}

My problem is the scoping of this.someValue(as an example I want to just print it). Everytime exists equals true the console logs undefined but it is not. If I would print it outside of fs.exists() then it has a value so I guess it is a scoping problem.

How can I access this.someValue in this sample?

Thanks in advance!

TorbenJ
  • 4,110
  • 9
  • 41
  • 77

3 Answers3

4

You have to .bind your inner function

MyClass.prototype.myFunction = function(file){
    if(some condition){
       fs.exists("./" + file, function(exists){
           if(exists)
               console.log(this.someValue);
               /* lot of other code */
           else
               /* do something else */
    }.bind(this));
    }else{
        /* do something */
    }
}

This can be rewritten to be cleaner

MyClass.prototype.myFunction = function myFunction(file){
  if(some condition){
    fs.exists("./" + file, this.doSomething.bind(this));
  }
  else{
    // do something else
  }
}

MyClass.prototype.doSomething = function doSomething(exists) {
  if(exists) {
    console.log(this.someValue);
    // lot of other code
  }
  else {
    // do something else
  }
}

I personally like this solution because it allows you to maintain excellent code composition and prevents you from nesting function(){ function(){ function(){ ... }}}. It also prevents you from having a bunch of var that = this; or var self = this; variables floating around having you wonder which scope is which.

.bind is slower, yes, but as minitech points out, it's certainly not going to be your bottleneck when compared to file access.

Thank you
  • 107,507
  • 28
  • 191
  • 224
  • Binding is one of the slowest ways of passing scope pointer into another function. And has slightly different application purpose. – moka Jul 08 '13 at 14:52
  • 1
    @MaksimsMihejevs: Slow relative to file access? Don’t micro-optimize… – Ry- Jul 08 '13 at 14:52
  • 1
    Not relative to file operation, but slow for such simple operation. In fact it is dramatic difference, please check out here: http://jsperf.com/bind-vs-closure-setup/6 – moka Jul 08 '13 at 14:56
  • @MaksimsMihejevs the original question, and this answer, both use it in the context of a `fs.exists()` callback. If it was in the middle of a tight loop, I'd agree with you, but when it's mixed in with file I/O the performance penalty background noise at worst, and `.bind()` does result in more easily understandable code (`this` all the way down). – deoxxa Jul 08 '13 at 15:06
  • i like your solution too. in fact it is much more readable for this use case :) I'll test it too but I think it is not that nice for bigger functions because of scrolling :) – TorbenJ Jul 08 '13 at 15:14
  • @deoxxa generally using .bind without real need - is not good style. That why I went a bit against it. Relative to performance - it is all fine and your points make obvious sense. But it is just not a good style to do so, especially if you are developing multi-team stuff and there is many places where function is executed from - can lead to big confusion generally. – moka Jul 08 '13 at 15:22
  • @MaksimsMihejevs can you define "good style"? Or explain how `var self = this;` is less confusing? – deoxxa Jul 08 '13 at 15:59
  • @deoxxa please read this great post: http://pmuellr.blogspot.co.uk/2010/06/bind-considered-harmful.html `.bind` has rare but real need, but that is really rare and very specific cases. Generally check link above it nearly covers everything related to bind. – moka Jul 08 '13 at 16:31
3
MyClass.prototype.myFunction = function(file){
  var that = this;
  // some lines of code later...
       console.log(that.someValue);
}
joewhite86
  • 418
  • 3
  • 6
2

As this - is keyword that is defined by scope of function and responds to owner or caller of a function. So you might store its pointer in another variable:

MyClass.prototype.myFunction = function(file) {
  if(some condition) {
    var self = this; // create variable with pointer to 'this'
    fs.exists("./" + file, function(exists) {
      if(exists) {
        console.log(self.someValue); // we can access it to parent scope variables
        /* lot of other code */
      } else {
        /* do something else */
      }
    });
  } else {
    /* do something */
  }
}

As well check out this brilliant topic: How does the "this" keyword work?

Community
  • 1
  • 1
moka
  • 21,690
  • 4
  • 48
  • 65