Quiz

What advantage is there for using the JavaScript arrow syntax for a method in a constructor?

Topics
JavaScript
Edit on GitHub

TL;DR

The main advantage of using an arrow function as a method inside a constructor is that the value of this gets set at the time of the function creation and can't change after that. When the constructor is used to create a new object, this will always refer to that object.

For example, let's say we have a Person constructor that takes a first name as an argument has two methods to console.log() that name, one as a regular function and one as an arrow function:

const Person = function (name) {
this.name = name;
this.sayName1 = function () {
console.log(this.name);
};
this.sayName2 = () => {
console.log(this.name);
};
};
const john = new Person('John');
const dave = new Person('Dave');
john.sayName1(); // John
john.sayName2(); // John
// The regular function can have its `this` value changed, but the arrow function cannot
john.sayName1.call(dave); // Dave (because `this` is now the dave object)
john.sayName2.call(dave); // John
john.sayName1.apply(dave); // Dave (because `this` is now the dave object)
john.sayName2.apply(dave); // John
john.sayName1.bind(dave)(); // Dave (because `this` is now the dave object)
john.sayName2.bind(dave)(); // John
const sayNameFromWindow1 = john.sayName1;
sayNameFromWindow1(); // undefined (because `this` is now the window object)
const sayNameFromWindow2 = john.sayName2;
sayNameFromWindow2(); // John

The main takeaway here is that this can be changed for a normal function, but this always stays the same for an arrow function. So even if you are passing around your arrow function to different parts of your application, you wouldn't have to worry about the value of this changing.


Arrow functions

Arrow functions are introduced in ES2015 and it provides a concise way to write functions in Javascript. One of the key features of arrow function is that it lexically bind the this value, which means that it takes the this value from enclosing scope.

Syntax

Arrow functions use the => syntax instead of the function keyword. The basic syntax is:

const myFunction = (arg1, arg2, ...argN) => {
// function body
};

If the function body has only one expression, you can omit the curly braces and the return keyword:

const myFunction = (arg1, arg2, ...argN) => expression;

Examples

// Arrow function with parameters
const multiply = (x, y) => x * y;
// Arrow function with no parameters
const sayHello = () => 'Hello, World!';

Advantages

  • Concise: Arrow functions provide a more concise syntax, especially for short functions.
  • Implicit return: They have an implicit return for single-line functions.
  • Value of this is predictable: Arrow functions lexically bind the this value, inheriting it from the enclosing scope.

Limitations

Arrow functions cannot be used as constructors and will throw an error when used with the new keyword.

const Foo = () => {};
const foo = new Foo(); // TypeError: Foo is not a constructor

They also do not have arguments keyword; the arguments have to be obtained from using the rest operator (...) in the arguments.

const arrowFunction = (...args) => {
console.log(arguments); // Throws a TypeError
console.log(args); // [1, 2, 3]
};
arrowFunction(1, 2, 3);

Since arrow functions do not have their own this, they are not suitable for defining methods in an object. Traditional function expressions or function declarations should be used instead.

const obj = {
value: 42,
getValue: () => this.value, // `this` does not refer to `obj`
};
console.log(obj.getValue()); // undefined

Why arrow functions are useful

One of the most notable features of arrow functions is their behavior with this. Unlike regular functions, arrow functions do not have their own this. Instead, they inherit this from the parent scope at the time they are defined. This makes arrow functions particularly useful for scenarios like event handlers, callbacks, and methods in classes.

Arrow functions inside function constructors

const Person = function (name) {
this.name = name;
this.sayName1 = function () {
console.log(this.name);
};
this.sayName2 = () => {
console.log(this.name);
};
};
const john = new Person('John');
const dave = new Person('Dave');
john.sayName1(); // John
john.sayName2(); // John
// The regular function can have its `this` value changed, but the arrow function cannot
john.sayName1.call(dave); // Dave (because `this` is now the dave object)
john.sayName2.call(dave); // John
john.sayName1.apply(dave); // Dave (because `this` is now the dave object)
john.sayName2.apply(dave); // John
john.sayName1.bind(dave)(); // Dave (because `this` is now the dave object)
john.sayName2.bind(dave)(); // John
const sayNameFromWindow1 = john.sayName1;
sayNameFromWindow1(); // undefined (because `this` is now the window object)
const sayNameFromWindow2 = john.sayName2;
sayNameFromWindow2(); // John

Arrow functions in event handlers

const button = document.getElementById('myButton');
button.addEventListener('click', function () {
console.log(this); // Output: Button
console.log(this === button); // Output: true
});
button.addEventListener('click', () => {
console.log(this); // Output: Window
console.log(this === window); // Output: true
});

This can be particularly helpful in React class components. If you define a class method for something such as a click handler using a normal function, and then you pass that click handler down into a child component as a prop, you will need to also bind this in the constructor of the parent component. If you instead use an arrow function, there is no need to bind this, as the method will automatically get its this value from its enclosing lexical context. See this article for an excellent demonstration and sample code.

Further reading

Edit on GitHub