When You Should Not Use Arrow Functions

Created with Sketch.

When You Should Not Use Arrow Functions

Summary: in this tutorial, you will learn when you should not use the arrow functions in ES6.

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.

1) Event handlers

Suppose that you have the following input text field:

<input type="text" name="username" id="username" placeholder="Enter a username">

Code language: HTML, XML (xml)

And you want to show a greeting message when users type their usernames. The following shows the <div> element that will display the greeting message:

<div id="greeting"></div>

Code language: HTML, XML (xml)

Once users type their usernames, you capture the current value of the input and update it to the <div> element:

const greeting = document.querySelector('#greeting');
const username = document.querySelector('#username');
username.addEventListener('keyup', () => {
greeting.textContent = 'Hello ' + this.value;
});

Code language: JavaScript (javascript)

However, when you execute the code, you will get the following message regardless of whatever you type:

Hello undefined

Code language: JavaScript (javascript)

It means that the this.value in the event handler always returns undefined.

As mentioned earlier, the arrow function doesn’t have its own this value. It uses the this value of the enclosing lexical scope. In the above example, the this in arrow function references the global object.

In the web browser, the global object is window. The window object doesn’t have the value property. Therefore, the JavaScript engine adds the value property to the window object and sets its values to undefined.

To fix this issue, you need to use a regular function instead. The this value will be bound to the <input> element that triggers the event.

username.addEventListener('keyup', function () {
input.textContent = 'Hello ' + this.value;
});

Code language: JavaScript (javascript)

2) Object methods

See the following counter object:

const counter = {
count: 0,
next: () => ++this.count,
current: () => this.count
};

Code language: JavaScript (javascript)

The counter object has two methods: current() and next(). The current() method returns the current counter value and the next() method returns the next counter value.

The following shows the next counter value which should be 1:

console.log(counter.next());

Code language: CSS (css)

However, it returns NaN.

The reason is that when you use the arrow function inside the object, it inherits the this value from the enclosing lexical scope which is the global scope in this example.

The this.count inside the next() method is equivalent to the window.count (in the web browser).

The window.count is undefined by default because the window object doesn’t have the count property. The next() method adds one to undefined that results in NaN.

To fix this, you use regular functions as the method of an object literal as follows:

const counter = {
count: 0,
next() {
return ++this.count;
},
current() {
return this.count;
}
};

Code language: JavaScript (javascript)

Now, calling the next() method will return one as expected:

console.log(counter.next()); // 1

Code language: JavaScript (javascript)

3) Prototype methods

See the following Counter object that uses the prototype pattern:

function Counter() {
this.count = 0;
}

Counter.prototype.next = () => {
return this.count;
};

Counter.prototype.current = () => {
return ++this.next;
}

Code language: JavaScript (javascript)

The this value in these next() and current() methods reference the global object. Since you want the this value inside the methods to reference the Counter object, you need to use the regular functions instead:

function Counter() {
this.count = 0;
}

Counter.prototype.next = function () {
return this.count;
};

Counter.prototype.current = function () {
return ++this.next;
}

Code language: JavaScript (javascript)

4) Functions that use the arguments object

Arrow functions don’t have the arguments object. Therefore, if you have a function that uses arguments object, you cannot use the arrow function.

For example, the following concat() function won’t work:

const concat = (separator) => {
let args = Array.prototype.slice.call(arguments, 1);
return args.join(separator);
}

Code language: JavaScript (javascript)

Instead, you use a regular function like this:

function concat(separator) {
let args = Array.prototype.slice.call(arguments, 1);
return args.join(separator);
}

Code language: JavaScript (javascript)

Summary

  • An arrow function doesn’t have its own this value. Instead, it uses the this value of the enclosing lexical scope. An arrow function also doesn’t have the arguments object.
  • Avoid using the arrow function for event handlers, object methods, prototype methods, and functions that use the arguments object.

Leave a Reply

Your email address will not be published. Required fields are marked *