kiseragi
kiseragi

Reputation: 15

Converting javascript arrow function to a normal function

I am currently going through the Angular tutorial and came across the following code:

getHero(id: number): Promise<Hero> {
    return this.getHeroes().then( heroes => heroes.find( hero => hero.id === id ));
}

Out of curiosity, I decided to rewrite the callback function using a normal function:

getHero(id: number): Promise<Hero> {
    return this.getHeroes().then( heroes => heroes.find( this.findHero, id));
}

findHero(hero: Hero, index: number, array: Hero[]): boolean {
    if(hero.id === this.id){
        return true;
    }else{
        return false;
    }
}

But this gives me the error Property 'id' does not exist on type 'HeroService'.

How may I refer to the id parameter passed to my callback function?

Upvotes: 0

Views: 173

Answers (1)

damianmr
damianmr

Reputation: 2531

The id (number) property is defined as an argument of the function getHero, thus, is not available in your function findHero. You tried to use this.id but the compiler is telling you that such a property does not exits in your class HeroService, which is correct of course, as if you wanted to have that property as part of your service then you would have to do something like this in your getHero method.

getHero(id: number, ...etc) {
    this.id = id;
    // etc.
}

However, that would bring you another problem: as your method getHeroes seems to be async code (I can tell because it is returning a Promise) this approach will cause you headaches with concurrency problems when your method getHero is called twice (or more times) from different parts of the application. The first getHero call will set this.id to x but in the meantime, while the async code is run, another call to getHero will set it to y, making that the callback findHero run in response to the first call use an incorrect value for the id(specifically, it will read y as the value for this.id).

So... long story short. You would probably want to read more about CLOSURES and why they are so important for JavaScript. Short answer to your question, use this:

getHero(id: number): Promise<Hero> {
    return this.getHeroes().then( heroes => heroes.find(this.findHero.bind(this, id));
}

And define your callback findHero as

findHero(idToFind: number, hero: Hero, index, array: Hero[]) {
    return hero.id === idToFind;
}

The reason why you need this is that the this is not passed automatically to the functions that you use as arguments for other functions (or methods, as in this case). So by using bind you explicitly BIND the this of such a function so that whenever you use this in findHero it points to the right object. The second argument of bind is binding the id you are looking for to every call of the function findHero, so that whenever the function returned by bind is called it happens two things:

  1. The this is bound to HeroService.
  2. Along with the arguments the function would normally receive, you are also binding another argument that will be automatically injected into the arguments of calls to that function.

Just one minor note... you are using TypeScript, so the this argument in your bind is pointless, as TypeScript automatically binds all methods in your class to the current instance, but you need it in this case because you also want to bind the second argument (the id to find).

I hope it I helped.

Upvotes: 2

Related Questions