0

class Foo {
  constructor() {
    this.foobar = "foobar";
  }
  bar() {
    let _this = this;
    return function() {
      try {
        alert("Attempt 1: "+foobar);//ReferenceError: foobar is not defined
        myMethod();
      } catch(err) {console.log(err);}
      try {
        alert("Attempt 2: "+this.foobar);//TypeError: this is undefined
        this.myMethod();
      } catch(err) {console.log(err);}
      try{
        alert("Attempt 3: "+_this.foobar);//Works!
        _this.myMethod();
      } catch(err) {console.log(err);}
    }();
  }
  myMethod() {
    alert("myMethod()");
  }
}
new Foo().bar();

The above example is very simplified - the anonymous function inside bar() was a jQuery call originally, but for the sake of the question I didn't include that.

Why don't attempts 1 and 2 work? Do I have to use the _this trick to reference class variables/methods? How do I reference class variables/methods from nested functions?

NonameSL
  • 1,220
  • 12
  • 23

3 Answers3

0

Are you familiar with how the this keyword works in JavaScript? It's value will depend on how the function is called, not in how it is defined. For example, if you do the following:

var dog = {
  greeting:"woof",
  talk:function (){
    console.log(this.greeting);
  }
};

var cat={
  greeting:"meow",
  talk:dog.talk
};

dog.talk();
cat.talk();

You will see that when the talk function is called as a method of an object, that object will be used as the value of this.

The same happens with ES6 classes, where class methods are still JavaScript functions and the rules for deciding the value of this still apply. If you want to avoid declaring an auxiliar variable, you should look into using bind:

var mammal = {
  greeting:"<noise>",
  getTalk:function (){
    return function(){
      console.log(this.greeting);
    };
  },
  getTalkBinded:function (){
    return (function(){
      console.log(this.greeting)
    }).bind(this);
  }
};

var dog={
  greeting:"woof",
  talk:mammal.getTalk(),
  talkBinded:mammal.getTalkBinded()
};

var cat={
  greeting:"meow",
  talk:mammal.getTalk(),
  talkBinded:mammal.getTalkBinded()
};

dog.talk();
cat.talk();
dog.talkBinded();
cat.talkBinded();
Arcadio Garcia
  • 431
  • 1
  • 4
  • 16
0

You are returning self-execution function execution result and during that function execution this it global context(not your class object). to make it work use () => {}() arrow function call syntax, as it captures current context, or function() { }.bind(this)().

Sergey Sahakyan
  • 587
  • 7
  • 12
0

See this simple example,

function a(){
    this.someProp = 5;
    console.log(this);

    var _this = this;   //so we explicitly store the value of `this` to use in a nested function

    return function(){
        //value of `this` will change inside this function
        this.anotherProp = 6;
        console.log(this);

        //to use the methods and props of original function use `_this`
        console.log(_this)
    }
}

var c = a.call({})  //prints {someProp: 5}
c.call({})    //prints {anotherProps: 6} {someProp: 5}
Anurag Awasthi
  • 5,401
  • 1
  • 13
  • 28