# Arrow Functions in JavaScript

Subscribe to my newsletter and never miss my upcoming articles

Arrow functions were introduced in ES6. But before diving deeper into arrow functions, let's see how we write functions in a traditional way:

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

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 * 2;
``````

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! 🌟