Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I write methods as arrow functions in Angular's class

In Angular it's technically possible to write class methods as ES2015 arrow functions, but I have never actually seen someone do it. Take this simple component for instance:

@Component({   selector: 'sample' }) export class SampleComponent {   arrowFunction = param => {     // Do something   };   normalFunction(param) {     // Do something   } } 

This works without any issues. Are there any differences? And why should or shouldn't I use this?

like image 936
Gideon Avatar asked Aug 25 '17 12:08

Gideon


People also ask

Should arrow functions be used as methods?

An arrow function doesn't have its own this value and the arguments object. Therefore, you should not use it as an event handler, a method of an object literal, a prototype method, or when you have a function that uses the arguments object.

Should I use arrow functions in classes?

You should avoid using arrow functions in class as they won't be the part of prototype and thus not shared by every instance. It is same as giving the same copy of function to every instance.

When should we use arrow functions?

Arrow functions intend to fix the problem where we need to access a property of this inside a callback. There are already several ways to do that: One could assign this to a variable, use bind , or use the third argument available on the Array aggregate methods.

When should I use arrow functions in Javascript?

Arrow functions introduce concise body syntax, or implicit return. This allows the omission of the curly brackets and the return keyword. Implicit return is useful for creating succinct one-line operations in map , filter , and other common array methods.


1 Answers

The points made in this React answer are still valid in Angular, any other framework or vanilla JavaScript/TypeScript.

Class prototype methods are ES6, class arrow methods aren't. Arrow methods belong to class fields proposal and not a part of existing specs. They are implemented in TypeScript and can be transpiled with Babel as well.

It's generally preferable to use prototype method() { ... } than arrow method = () => { ... } because it's more flexible.

Callbacks

The only real opportunity that arrow method provides is that it it can be seamlessly used as a callback:

class Class {   method = () => { ... } }  registerCallback(new Class().method); 

If prototype method should be used as a callback it should be additionally bound, this should be preferably be done in constructor:

class Class {   constructor() {     this.method = this.method.bind(this);   }    method() { ... } }  registerCallback(new Class().method); 

A decorator like bind-decorator can be used in TypeScript and ES Next to provide more concise alternative to method binding in constructor:

import bind from 'bind-decorator';  class Class {   @bind   method() { ... } } 

Inheritance

Arrow method restricts child classes to use arrow methods too, otherwise they won't be overridden. This creates a problem if an arrow was overlooked:

class Parent {   method = () => { ... } }  class Child extends Parent {   method() { ... } // won't override Parent method } 

It's not possible to use super.method() in child class because super.method refers to Parent.prototype.method, which doesn't exist:

class Parent {   method = () => { ... } }  class Child extends Parent {   method = () => {     super.method(); // won't work     ...   } } 

Mixins

Prototype methods can be efficiently used in mixins. Mixins are useful for multiple inheritance or to fix problems in TypeScript method visibility.

Since arrow method isn't available on class prototype, it can't be reached from outside the class:

class Parent {   method = () => { ... } }  class Child extends OtherParent { ... } Object.assign(Child.prototype, Parent.prototype) // method won't be copied 

Testing

A valuable feature that prototype methods provide is that they are accessible before class instantiation, thus they can be spied or mocked in tests, even if they are called right after construction:

class Class {   constructor(arg) {     this.init(arg);   }    init(arg) { ... } }  spyOn(Class.prototype, 'init').and.callThrough(); const object = new Class(1); expect(object.init).toHaveBeenCalledWith(1); 

This is not possible when a method is an arrow.

TL;DR: the choice between prototype and arrow class methods seems like a matter of taste, but in reality the use of prototype methods is more far-sighted. You may usually want to avoid arrow class methods, unless you are sure that they will cause no inconvenience. Don't forget to use bind on prototype methods if you pass them as callbacks.

like image 182
Estus Flask Avatar answered Oct 13 '22 20:10

Estus Flask