Follow

# Slashism

Follow # Arrow Functions in JavaScript

Pankaj Sanam
·Oct 26, 2020·

Arrow functions are a new way of writing a traditional function. This way the function is shorter and quicker to write. Arrow functions were introduced in ES6.

Let's see how we write functions in a traditional way:

``````const sum = function(a, b) {
return a + b;
}
``````

Now let's transform this traditional function into an arrow function:

``````const sum = (a, b) => {
return a + b;
}
``````

So what do you notice? The `function` keyword is removed and an arrow `=>` is added for the expression.

We can simplify the above example a little more by removing the `return` statement:

``````const sum = (a, b) => a + b;
``````

Do you notice how the curly braces and `return` is gone? Remember, that you can only do this if the first line of the function body is a `return` statement.

In the above example, we have two parameters `a` and `b`. But what if there was only one parameter? Then we can make it even shorter:

``````const income = salary => salary * 10;
``````

We have removed the parenthesis as well because there was only one parameter `salary`. Remember that we can't do this if there is no parameter or parameters are more than one.

Let's do the sorting of numbers with both traditional and arrow functions:

``````// Traditional style
const numbers = [36, 12, 16, 22];

numbers.sort(function(a, b) {
return a - b;
});

console.log(numbers); // [12, 16, 22, 36]
``````

Let's do the same example with the arrow function:

``````// Arrow function
const numbers = [36, 12, 16, 22];

numbers.sort((a, b) => a - b);

console.log(numbers); // [12, 16, 22, 36]
``````

That's short and simple. ❤

You might want to watch out while returning an object in an arrow function. You can't do it like this:

``````// won't work ❌
const profile = () => { name: 'Dovahkiin', address: 'The Cloud District, Whiterun' };
``````

The correct way is, by wrapping the object in parenthesis like this:

``````// it works ✔
const profile = () => ({ name: 'Dovahkiin', address: 'The Cloud District, Whiterun' });
``````

That's the cosmetic difference between our good old traditional function declaration and the new arrow function. But there is more to it than these fancy changes. ⚡

## Let's talk about `this`

Traditional functions have their own `this` binding while arrow functions don't. Arrow functions can only access `this` from their parent scope. So if you use `this` in an arrow function then it will refer to the object of that arrow function's parent.

Let's understand this by an example:

``````window.age = 130;

function EdwardCullen() {
this.age = 17;

setTimeout(function () {
// this.age is not declared in this scope so it defaults to the window scope
console.log(`Edward Cullen is \${this.age} old.`); // "130"
}, 1);
}

const vampire = new EdwardCullen();
``````

In the above example, we have set the age to `130` on `window` object. Now inside the `EdwardCullen` we have `setTimeout` declared in a traditional way by using `function()`.

Now if you try to print `this.age` in `setTimeout`, you will get `130` which was declared directly as `window` object.

Do you know why? Because `setTimeout` does not have it's own `this.age` declared inside it. So it fetches it by default from the `window` object. It doesn't care about `this.age` declared in the parent scope.

Let's see the above example using the arrow function:

``````window.age = 130;

function EdwardCullen() {
this.age = 17;

setTimeout(() => {
// there is no `this` scope in arrow function so it takes this.age from it's parent scope
console.log(`Edward Cullen is \${this.age} old.`); // "17"
}, 1);
}

const vampire = new EdwardCullen();
``````

Now `this.age` inside `setTimeout` prints `17` instead of printing the age from `window` scope. Our arrow function `setTimeout` tries to find `this` in the immediate lexical scope of the parent rather than looking in the `window` scope.

This eliminates the confusion and issues with traditional function declaration where `this` might work in an unexpected and confusing way.

Let's take another example to understand this:

``````// Traditional way
function EdwardCullen() {
this.age = 17;

this.realAge = function (age) {
this.age = age;

setTimeout(function () {
console.log(this.age); // undefined
}, 1);
};
}

const vampire = new EdwardCullen();
vampire.realAge(120);
``````

The above example prints `undefined` because `this.age` is not defined inside `setTimeout` function. Our traditional function, expects it to be defined in the function itself, if not then it seeks that information in `window` object. Here we don't have `age` in `window` object either. So it prints `undefined`.

Can we fix this without using an arrow function? Let's see:

``````function EdwardCullen() {
this.age = 17;

this.realAge = function (age) {
this.age = age;
const self = this;

setTimeout(function () {
console.log(self.age); 120
}, 1);
};
}

const vampire = new EdwardCullen();
vampire.realAge(120);
``````

Do you notice `let self = this`? This way we can store `this` in another variable named `self` and then we can use `self.age` inside `setTimeout` instead of using `this`. Now it prints `120` correctly. This is how we used to solve this problem before arrow functions.

Well, we have the arrow functions now so we don't have to do this little hack any more:

``````function EdwardCullen() {
this.age = 17;

this.realAge = function (age) {
this.age = age;

setTimeout(() => console.log(this.age); 120, 1);
};
}

let vampire = new EdwardCullen();
vampire.realAge(120);
``````

Here we changed the traditional `setTimeout` function to an arrow function and it printed `120` correctly. We didn't have to do the `self` hack to achieve this. It worked because the arrow function got no binding for `this` for itself so it tries to find the binding from the parent function which is declared as `120` in `age` parameter of `realAge` method.

## Limitations of Arrow functions

Arrow functions remove the complexity of `this` but that comes with some limitations:

### 1. Shouldn't be used as methods

It is not recommended to use arrow functions as methods because of the unexpected results. Let's understand this by an example:

``````const edwardCullen = {
age: 17,

getAge: function() {
console.log(this.age);
},

getRealAge: () => console.log(this.age),
}

edwardCullen.getAge(); // 17
edwardCullen.getRealAge(); // undefined
``````

As you can see in the above example, `getAge` is using the window object with normal function so it prints `10` while the `getRealAge` function has no binding and no near lexical scope inside `edwardCullen` so it will print `undefined`

In this, particular case, we should stick with `getAge` by using traditional function declaration. Arrow functions are not a good fit for such cases as evident in the above example.

### 2. `apply`, `bind` and `call` shouldn't be used

`apply`,`bind`, and `call` work as expected with traditional functions, because we establish the scope for each of the methods but it's not the case with arrow functions.

Let's take a look at the traditional way first:

``````// Traditional function
const edwardCullen = {
age: 17
};

window.age = 120;

const realAge = function(a, b, c) {
return this.age + a + b + c;
}

// call
const firstGuess = realAge.call(edwardCullen, 10, 20, 30);
console.log(firstGuess); // 77

// apply
const secondGuess = realAge.apply(edwardCullen, [10, 20, 30]);
console.log(secondGuess); // 77

// bind
const thirdGuess = realAge.bind(edwardCullen);
console.log(thirdGuess(10, 20, 30)); // 77
``````

We get the age `77` if we use the traditional function.

``````// Arrow function
const edwardCullen = {
age: 17
};

window.age = 120;

const realAge = (a, b, c) => this.age + a + b + c;

// call
const firstGuess = realAge.call(edwardCullen, 10, 20, 30);
console.log(firstGuess); // 180

// apply
const secondGuess = realAge.apply(edwardCullen, [10, 20, 30]);
console.log(secondGuess); // 180

// bind
const thirdGuess = realAge.bind(edwardCullen);
console.log(thirdGuess(10, 20, 30)); // 180
``````

We get the age `180` if we use the arrow function. 😁

Now you can see the difference and why it is suggested NOT to use `apply`, `bind` and `call` with arrow functions.

### 3. Can not be used as `constructors`

Arrow functions cannot be used as constructors and they don't have `prototype` property as well:

``````const nightCreature = () => 'Edward Cullen';
const vampire = new nightCreature(); // TypeError: nightCreature is not a constructor
``````
``````const nightCreature = () => 'Edward Cullen';
console.log(nightCreature.prototype); // undefined
``````

I hope you learned something today!

Stay awesome! 🌟