3

Given a simple typeScript class:

class Greeter {
  greeting: string;

  constructor(message: string) {
    this.greeting = message;
  }

  greet() {
    return "Hello, " + this.greeting;
  }

  thisworks(input) {
    console.log("I am " + input) ;
  }

  doesNotWork(input) {
    return "Hi " + this.greeting +". I am " + input;
  }   
}

an array:

let myArray = ["Joe","William","Jack","Averell"];

and a function:

let myFunction = (name) => {
  let obj = new Greeter(name);
  console.log(obj.greet());
};

I can map the array and execute the function for each value:

async.map(
  myArray,
  myFunction
);

Or I can map the array and execute a class method with each value:

let myInput = new Greeter("John");

async.map(
  myArray,
  myInput.thisworks
);

But I cannot map the array, passing each value to a class method, and access the class property at the same time:

let myInput = new Greeter("Bill");

async.map(
  myArray,
  myInput.doesNotWork
);

Can someone please explain why the last example does not work? And how to make it work?

I expected the result with the last example to be:

Hi Bill. I am Joe
Hi Bill. I am William
Hi Bill. I am Jack
Hi Bill. I am Averell

Instead, I get the following error:

Uncaught TypeError: Cannot read property 'greeting' of undefined

Here is a plunk associated with this question

Manube
  • 5,110
  • 3
  • 35
  • 59
  • Basically the same scope problem as everyone gets. `myInput.doesNotWork` is called with a `this` which refers to something other than `myInput`. Either bind it to the correct context like `myInput.doesNotWork.bind(myInput)` or use a function call like `(item) => myInput.doesNotWork(item)`... – Heretic Monkey Jan 16 '17 at 21:44
  • 1
    Related: http://stackoverflow.com/q/14471975/266535 – styfle Jan 16 '17 at 21:50

1 Answers1

1

This is a problem with lexical this.

The solution is to make sure you bind this when the function is created or when the function is called.

Bind this when function is created

class Greeter {
    greeting: string;

    constructor(message: string) {
      this.greeting = message;
    }

    doesNotWork = (input) => {
      console.log("Hi " + this.greeting +". I am " + input);
    }

}

OR

Bind this at call site

let myInput = new Greeter("Bill");
async.map(
    myArray,
    myInput.doesNotWork.bind(myInput)
);  
styfle
  • 22,361
  • 27
  • 86
  • 128