TorbenJ
TorbenJ

Reputation: 4582

Variable scope in callback function

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!

Upvotes: 2

Views: 145

Answers (3)

moka
moka

Reputation: 23047

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?

Upvotes: 2

Mulan
Mulan

Reputation: 135197

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.

Upvotes: 4

joewhite86
joewhite86

Reputation: 418

MyClass.prototype.myFunction = function(file){
  var that = this;
  // some lines of code later...
       console.log(that.someValue);
}

Upvotes: 3

Related Questions