Javascript: ES6 Arrow Functions Dymystified

Faruk Nasir
5 min readDec 19, 2018

--

Premise

Have you ever come across a situation while programming in JavaScript where you are passing a function as an argument to another function and you can’t get the this to work as you want it to because the outside function has a this different from the inner one?

Yeah, me too.

function countup() {

this.x = 0;

setInterval(function() {

console.log(this.x++); // this prints ‘NaN’ to the console

}, 1000);

}

If you run the above snippet, NaN will continuously be printed on the console. Why is that?

In the countup function, we initialized the this.x to 0. And in the setInterval function we tried to increment the x variable and writing it to the console using the this keyword which was not possible because in javascript, every function written is automatically assigned a this attribute and they don’t have to want it.

To work around this, programmers try to create another variable and initialiase the this to it so as to be able to call it subsequently in any function within or passed as an argument.

function countup() {

let self = this;

self.x = 0;

setInterval(function() {

console.log(self.x++);

}, 1000);

}

After running the above code, numbers will be printed continuously on the console as they are incremented. This is a quick workaround that has saved programmers from a lot of trouble. But, there is a better fix. And I will discuss that in a bit.

What is an Arrow Function?

An arrow function(fat arrow function) is a concise way of writing a function. It was introduced in ECMAScript 2015 or ES6. It saves time, simplify function scope and is, arguably, the most popular and widely loved feature of the ES6. It is anonymous. That is, an arrow function is a non-named function — an attribute that makes it harder to debug than normal JavaScript functions.

SYNTAX

At its basics, an arrow function is written as follows:

( param1, param2…paramX ) => { //statements }

Parentheses are optional when there is only one argument

( onlyOneParam ) => { //statements }

//can be conveniently written as

onlyOneParam => { //statements }

But, parentheses are required when there is no argument

() => { //statements }

In other to return object literals, the body of a function should be wrapped with parentheses.

params => ({ foo:bar })

The introduction of arrow functions

There are two main ideas that motivated the introduction of arrow functions. These are:

  • Shorter Functions
  • Absence of this

Shorter Functions

var employees = {

“Faruk”,

“Ibrahim”,

“Sadik”,

“Jeremiah”

};

// es5

employees.map( function(employees) {

return employees.length;

});

// es6

employees.map(employees => employees.length);

Absence of this

Above, in the premise section, I described a plight that most JavaScript programmers go through at least once in their programmer life time. I, then, went on to, briefly, discuss a work around that most of us fall back to by default. And then towards the end of the section, I made a bold claim of having a better fix in my secret vault that I will reveal in a bit. Well, now is that time!

But, before we continue, what is lexical scoping?

Lexical Scoping, also referred to as static scoping, is a convention used with many programming languages that sets the range of functionality of a variable so that it may be called from within the block of code in which it is defined.

An arrow function does not have its own native this. It uses the this from the function or block of code containing the arrow function. Arrow functions leverage the concept of lexical scoping in handling the this dilemma.

Lets use an arrow function to fix the countup() function above.

function countup() {

this.x = 0;

setInterval(() => {

console.log(this.x++);

}, 1000);

}

Running this snippet, you’ll have the same output as the fix to the countup() function in the premise section. By just changing the function passed to the setInterval from a conventional one to an arrow function, the desired behaviour is achieved, without having to introduce an extra variable to capture the this scope for future reference.

Strict Mode

Arrow functions do not have their own this. Any this used in an arrow function comes from the surrounding lexical context. So the use of strict mode in an arrow function will have no effect: the strict mode rules with regard to this will be ignored.

//run this on the cmd

var testingStrictMode = () => {

‘use strict’;

return this;

}

testingStrictMode() === global; // true

If the strict mode within the arrow function above was working, the last line would have returned false. This is telling us that the scope of this in the testingStrictMode function is global despite using strict mode within the function. Apart from the strict mode rules related to this, all other strict mode rules apply normally.

To read more on strict mode and how to use it, head over to MDN Web Docs

call() and apply()

call() is a JavaScript method used to call another method that can be used on different objects. It allows an object to use a method belonging to another object.

var employee = {

fullname: function() {

return this.firstName + ‘ ‘ + this.lastName;

}

}

var employee1 = {

firstName: ‘Faruk’,

lastName: ‘Nasir’

}

employee.fullname.call(employee1); // Faruk Nasir

Let’s transform the fullname() function into an arrow function and see what happens.

var employee = {

fullname: () => {

return this.firstName + ‘ ‘ + this.lastName;

}

}

var employee1 = {

firstName: ‘Faruk’,

lastName: ‘Nasir’

}

employee.fullname.call(employee1); // undefined undefined

It returns ‘undefined undefined’ because this does not have any meaning inside an arrow function. To use the call() with an arrow function, we have to pass arguments to it.

var employee = {

fullname: (firstName, lastName) => {

return firstName + ‘ ‘ + lastName;

}

}

var employee1 = {

firstName: ‘Faruk’,

lastName: ‘Nasir’

}

employee.fullname.call(null, employee1.firstName, employee2.lastName); // Faruk Nasir

Arguments Binding

Arrow functions do not have their own arguments object.

var args = [1, 2, 3]

var argArray = () => args[0];

argArray(); // 1

Usage as methods

Arrow functions are best for non-method functions.

var x = {

a: 10,

b: () => console.log(this.a, this),

c: function() {

console.log(this.a, this)

}

}

x.b(); //prints undefined

x.c(); // prints 10

The new operator

Arrow functions can not be used as constructors.

var bar = () => {};

var foo = new bar(); //TypeError: bar is not a constructor

prototype property

Arrow functions do not have a prototype property.

var thisFunc = () => {};

console.log(thisFunc.prototype);

The yield keyword

Arrow functions can not be used as generators because the yield keyword may not be used in an arrow function’s body.

--

--