Chocksmith Chocksmith -4 years ago 166
TypeScript Question

Method x fat arrow in TypeScript

What is the difference between:

export class Test {

x: any;

processData = (data) => {
console.log("This=",this);
this.x = data;
console.log("Loaded.", data);
}
}


and this:

export class Test {

x: any;

processData(data) {
console.log("This=",this);
this.x = data;
console.log("Loaded.", data);
}

}


For the last one, in the following code:

ionViewLoaded() {
console.log("## ionViewDidLoad");
this.myApi.getPromise().then(this.processData);
}


the function ionViewLoaded() does not work because this==null inside processData()

Answer Source

this is actually precisely === undefined under strict mode in the second example. The difference is that all arrow functions close over the lexical this value of the scope in which they are created.

In your first example:

export class Test {

  x: {}; // Please stop using any.

  processData = (data) => {
    console.log("This=", this);
    this.x = data; 
    console.log("Loaded.", data);
  }
}

that lexical context is the instance of the enclosing class as you are defining an instance property, not a prototype method, the value of which is an arrow function closed.

In the second example:

export class Test {

  x: {};// Please stop using any.

  processData(data) {
    console.log("This=", this);
    this.x = data; 
    console.log("Loaded.", data);
  }

}

You are creating a method on the class prototype. A method has a dynamically scoped this reference that is bound at invocation time when it is called.

If you call it as object.method(), this will refer to object inside of method for that invocation and that invocation only.

If you call it as method(), that is with no receiving object, and if you running in strict mode, then this will be undefined inside of method for that invocation and that invocation only.

If you are not running in strict mode, this will refer to the global object. For example in a browser it will refer to window. This is very bad. Always run in strict mode.

Code is implicitly in strict mode inside of ES Modules and class bodies. You can set strict mode explicitly by beginning the enclosing file or enclosing function with the 'use strict'; directive prologue.

That is why the code fails in your second example, because this is undefined. In order to pass a method as a callback you need to bind it first. That is to say you would write

ionViewLoaded() {
  console.log("## ionViewDidLoad");
  this.myApi.getPromise().then(this.processData.bind(this));
}

Alternately you could create an arrow function that closed over the instance and the method at use site as in

ionViewLoaded() {
  console.log("## ionViewDidLoad");
  this.myApi.getPromise().then(data => this.processData(data));
}

or just use an arrow function bound to a property as in your first example.

Oh, and if the comments didn't give you the hint, please do not annotate anything with the any type.

I hope that helps.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download