Introducing JavaScript Arrow Functions
Tags: functional, oop, javascript, beginners
Published: 2020-01-04 03:43:06

**Subscribe to my email list now at http://jauyeung.net/subscribe/**

**Follow me on Twitter at https://twitter.com/AuMayeung**

**Many more articles at https://medium.com/@hohanga**

Arrow functions are a new type of functions introduced with ES2015 that provides an alternative compact syntax to functions declares with the `function` keyword. They don’t have their own bindings to `this`, `argument`, `super` or `new.target` keywords. This means that they aren’t suited for methods since they don’t bind to `this`, `argument`, or `super`. This also means that they can’t be used as constructors.

Declare Arrow Functions
=======================

To declare arrow functions, we can write the following if the function is one line long:

```javascript
() => 2
```

The function above returns the number 2. Notice that for functions that are only one line long, we don’t need the `return` keyword to return anything. Whatever is at the end is returned. Also notice that if it’s has no parameters than we need to put empty parentheses for the function signature. If there’s one parameter, then we can write something like:

```javascript
x => x*2
```

The function above takes in a parameter `x` and multiplies `x` by 2 and then return it. Notice that for arrow functions that only has one parameter, we don’t need to wrap it inside parentheses. If we have more than 1 parameter, then we need parentheses around the parameters, like in the following code:

```javascript
(x,y) => x*y
```

In the function above, we take `x` and `y` as parameters and return `x*y` . If we want to return an object literal in a one-line arrow function, we have to put parentheses around the object literal that we want to return. For example, we write something like:

```javascript
() => ({ a: 1, b: 2 });
```

to return the object `{ a: 1, b: 2 }` .

If we need to define a function that spans multiple lines, then we need to wrap curly brackets around the function’s code as we have below:

```javascript
(x, y) => {  
  return x+y;  
}
```

So the general syntax for arrow functions are one of the following:

```
(p1, p2, …, pN) => { statements } (p1, p2, …, pN) => expression  
  
(p) => { statements }p => { statements }  
  
() => { statements }
```

Default Parameters
==================

Arrow functions’ parameters can have default values set for them so that we can kip them when are calling functions and still get a value set to them. Default parameters is easy with JavaScript. To set them in our code, we write the following:

```javascript
const sum = (a,b=1) => a+b
```

In the code above, we set the default parameter value of `b` to 1, so if the second argument isn’t passed in when we call the `sum` function, then `b` is automatically set to 1. So if we call `sum` as follows:

```javascript
sum(1)
```

we get 2 returned.

As we can see, now we don’t have to worry about having optional arguments being `undefined` , which would be the alternative result if no default value if set for parameters. This eliminates many sources of errors that occurs when making parameters optional with JavaScript.

The alternative way without using default parameters would be to check if each parameter is `undefined` . We write the following to do this:

```javascript
const sum = (a,b,c)=>{  
  if (typeof b === 'undefined'){  
    b = 1;  
  }if (typeof c === 'undefined'){  
    c = 1;  
  }  
  return a+b+c;  
}
```

If we call the following `sum` function without some parameters, then we get:

```javascript
const sum = (a,b = 1,c = 1)=> a+b+c;  
sum(1) // returns 3  
sum(1, 2) // returns 4
```

As we can see, we handled missing parameters gracefully with default parameters.

For default parameters, passing in `undefined` is the same as skipping the parameters. For example, if we call the following function and pass in `undefined` , then we get:

```javascript
const sum = (a,b = 1,c = 1)=> a+b+c;  
sum(1,undefined) // returns 3  
sum(1,undefined,undefined) // returns 3  
sum(1, 2,undefined) // returns 4
```

Note that `undefined` is the same as skipping parameters. This isn’t true for other falsy values that are passed into a function. So if we pass in 0, `null` , `false` , or empty string, then they get passed in, and the default parameter values will be overwritten. For example, if we have the code below:

```javascript
const test = (num=1) => typeof num;  
test(undefined);  
test(null);  
test('');  
test(0);  
test(false);
```

We get `number` for `test(undefined)` , `object` for `test(null)` , `string` for `test(string)` , `number` for `test(0)` , and `boolean` for `test(false)` . This means that anything other than `undefined` is passed in, but note that if we pass in falsy values and then run arithmetic operations on them, then falsy values get converted to 0.

```javascript
const sum = (a,b = 1,c = 1)=> a+b+c;  
sum(1,null)  
sum(1,null,false)  
sum(1, 2,'')
```

So `sum(1, null)` returns 2 since `b` is converted to 0 and `c` has the default value of 1. `sum(1)` returns 1 since `b` and `c` are converted to 0. `sum(1, 2,’’)` is 3 since `a` is 1, `b` is passed in so that it becomes 2 instead of getting the default value of 1, and `c` is an empty string which is converted to 0.

Default arguments are evaluated at call time so that they’re set each time they’re called if no argument is passed into the function parameter with default values. For example, if we have:

```javascript
const append = (val, arr = [])=>{  
  arr.push(val);  
  return arr;  
}
append(1);  
append(2);
```

`append(1)` returns `[1]` and `append(2)` returns `[2]` since we didn’t pass in an array to each function call, so `arr` is set to an empty array each time it’s run.

It’s also important to know that we can pass in values returned by functions in the default parameter, so if we a function that returns something, we can call it in the default parameter and assign the returned value to the parameter. For example, we can write:

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

Then if we call `sum(1)` , we get 3 since `fn` function returns 2. This is very handy if we want to manipulate and combine values beforehand before assigning it as a parameter.

Another great feature of the default parameters is that the parameters left of the given parameter is available for the parameter for assignment as default values, so we can have a function like the function below:

```javascript
const saySomething = (name, somethingToSay, message = \`Hi ${name}. ${somethingToSay}`) => ({  
  name,  
  somethingToSay,  
  message  
});
```

Notice that we assigned an expression to the `message` parameter in the `saySomething` function. This is great for manipulating data and then assigning as we did before by assigning the function. We can also see that we can have default parameters that depend on parameters that are to the left of it. This means that default parameters to not have to be static.

So we call it with the first 2 parameters filled in, like `saySomething(‘Jane’, ‘How are you doing?’)`. We get:

```javascript
{name: "Jane", somethingToSay: "How are you doing?", message: "Hi Jane. How are you doing?"}
```

The `message` is returned with the template string that we defined evaluated.

We cannot call functions nested inside a function to get the returned value as the default parameter value. For example, if we write:

```javascript
const fn = (a = innerFn()) => {  
  const innerFn = () => { return 'abc'; }  
}
```

This will result in a `ReferenceError` being thrown because the inner function isn’t defined yet when the default parameter is defined.

We can also have default parameter values that are set to the left of the required parameters. Arguments are still passed into parameters from the left to the right, so is we have:

```javascript
const sum = (a=1,b) => a+b
```

If we have `sum(1)` we have `NaN` return 1 is added to `undefined` since we didn’t pas in anything for the second argument, `b` is `undefined` . However, if we write `sum(1,2)` then 3 is returned since we have `a` set to 1 and `b` set to 2.

Finally, we can use destructuring assignment to set default parameter values. For example, we can write:

```javascript
const sum = ([a,b] = [1,2], {c:c} = {c:3}) => a+b+c;
```

Then we call `sum` without arguments we get 6 since `a` is set to 1, `b` is set to 2, and `c` is set to 3 by the destructuring assignment feature that JavaScript provides.


This Object
===========

If `this` is referenced in a regular function declared with the `function` keyword, the `this` object isn’t set inside an arrow function to the function that has the `this` inside. If an arrow function is inside a constructor, then `this` is set to the new object. If it’s not inside any object, then `this` inside the arrow function is `undefined` in strict mode. `this` will be set to the base object if the arrow function is inside an object. However, we always get the `window` object if we reference `this` in an arrow function. For example, if we log `this` inside an arrow function that’s not inside a constructor or class like in the following code:

```javascript
const fn = () => thisconsole.log(fn);
```

We get the `window` object logged when `console.log` is run. Likewise, if we ran:

```javascript
let obj = {}  
obj.f = () => {  
  return this;  
};  
console.log(obj.f());
```

We get the same thing as we got before. This is in contrast to the tradition functions declared with the `function` keyword. If we replace the functions above with traditional functions in the code above, like in the following code:

```javascript
const fn = function() {  
  return this  
};  
console.log(fn);
```

We get the function `fn` that we declared logged for `fn`.

However, if the arrow function is inside a constructor, we get the object that it’s the property of as the value of `this`. For example, if we have:

```javascript
const obj = function() {  
  this.fn = () => this;  
}
console.log(new obj().fn())
```

Then `this` will be the current object the `this.fn` function is in, which is `obj`, so `obj` will be logged by `console.log(new obj().fn())` . Also, if we have the code below:

```javascript
let obj = {}  
obj.f = function() {  
  return this;  
};  
console.log(obj.f());
```

We get the `obj` object logged when it’s run.

When arrow functions are called with `call` and `apply` , the argument for the `this` object will be ignored. This means that they can’t be used to change the `this` object. For example, if we have:

```javascript
function add(a) {  
  return this.base + a;  
}  
console.log(add.call({  
  base: 1  
}, 2));
```

We get 3 logged. This means that we can pass in an object that we want for `this` and get its value with traditional functions. This wouldn’t work with arrow functions. If we have:

```javascript
const add = (a) => {  
  return this.base + a;  
}  
console.log(add.call({  
  base: 1  
}, 2));
```

We get `NaN` because `this` is `window`, which doesn’t have the `base` property. The first argument for `call` is ignored. Likewise, if we try to set the value of `this` inside the function when we use `apply`, we can do that with traditional functions:

```javascript
function add(a) {   
  return this.base + a;  
}  
console.log(add.apply({  
  base: 1  
}, [1]));
```

We get 2 logged since the first argument for `apply` is the `this` object for the function inside. This means that we can change `this.base` to 1 by passing in our own object for the first argument of `apply`. When we try the same thing with arrow functions like in the following code:

```javascript
const add = (a) => {   
  return this.base + a;  
}  
console.log(add.apply({  
  base: 1  
}, [1]));
```

We get `NaN` because `this.base` is `undefined` . Again `this` is set to the `window` object since we have an arrow function, so `this` cannot be changed with the `apply` function.

The `arguments` object isn’t bound to an arrow function, so we can’t use the `arguments` object to get the arguments passed into a function call of an arrow function. If we have a traditional, we can get the arguments passed in with the `arguments` object like the following code:

```javascript
function add(){  
  return [...arguments].reduce((a,b) => +a + +b, [])  
}  
console.log(add(1,2,3));
```

We get 6 logged in the last line. This is because the `arguments` object had all the arguments of the object in string form. So `arguments` would have `'1'` , `'2'` , and `'3'` listed. However, if we try to do that we an arrow function, we can’t get the sum of the arguments with the `arguments` object. For example, if we have:

```javascript
const add = () => [...arguments].reduce((a,b) => +a + +b, [])  
  
console.log(add(1,2,3));
```

We get `NaN` because we didn’t get the arguments of the function call in the `arguments` object.

Arrow functions can’t be used as constructors, therefore we can’t instantiate it with the`new` keyword. For example, if we write the following and run it:

```javascript
const Obj = () => {};  
let obj = new Obj();
```

We would get a `TypeError` .

Also, arrow functions don’t have a `prototype` property, so when we log something like:

```javascript
const Obj = () => {};  
console.log(Obj.prototype);
```

We get `undefined` . This means we can‘t inherit from an arrow function. The `yield` keyword can’t be used in an arrow’s functions’s body. Therefore, we can’t use arrow functions as generator functions.

Arrow functions are useful for times when we need to write a function more concisely than writing traditional functions and we don’t need to change the content of the `this` object inside the function. Also, we can’t use them for generator functions or constructor since they don’t have their own `this` object. They also don’t have the `prototype` property so they can’t be inherited from. Also, the arguments of an arrow function call cannot be retrieved from the `arguments` object, so we just get them explicitly from the parameters.