# Functions in JavaScript

Source: https://tpiros.dev/blog/functions-in-javascript-es2015

ES2015 gave us a new way to write functions: the arrow function syntax. It's terser, yes. But it also changes how `this` behaves, and that matters more than you'd think.

Functions are chunks of your code that perform a specific task. The key thing about them? They're reusable. You write them once, call them wherever you need them.

Say we've got an application that needs to greet people. We wouldn't want to scatter `console.log('Hello [name]')` all over the place. So we wrap that logic in a function and call it when needed:

```javascript
function greet(name) {
  return 'Hello' + name;
}

console.log(greet('Steve')); // Hello Steve
console.log(greet('Ann')); // Hello Ann
```

Real-world functions tend to be bigger and more involved, of course.

## arrow functions

Arrow functions (sometimes called 'fat arrow' functions) let you define functions more concisely in ES2015.

You've probably written something like this before:

```javascript
const numbers = [0, 1, 2];
numbers.map(function (number) {
  return console.log(number);
});
```

We can rewrite that with an arrow function by dropping the `function` keyword and replacing it with `=>`. There are some rules around how arguments and the `return` keyword work (we'll get to those shortly):

```javascript
const numbers = [0, 1, 2];
numbers.map((number) => console.log(number));
```

### `this`

The difference between regular functions and arrow functions isn't just shorter syntax. Arrow functions bind `this` lexically to the calling function.

That sentence probably feels a bit confusing (excuse the pun). Let's look at how `this` works in regular JavaScript.

Here's a relatively simple example. We've got a JavaScript object that calculates quotients:

```javascript
const quotient = {
  numbers: [1, 2, 3, 4, 5, 6, 7],
  results: [],
  divideFn: function (divisor) {
    return this.numbers.map(function (divident) {
      if (divident % divisor === 0) {
        return this.results.push(divident);
      }
    });
  },
};
```

We store a sample dataset in `numbers`, collect results in `results`, and use `divideFn()` to iterate through each number. If the modulo operator (`%`) returns 0 (meaning the number is divisible), we push it into our results array.

To find numbers divisible by 3, add these two lines:

```javascript
quotient.divideFn(3);
console.log(quotient.results);
```

Run this and you'll hit an error: `Cannot read property 'push' of undefined`. That's odd. `results` is definitely an array, so it should have a `push()` method.

Start debugging and you'll spot the culprit: the execution context and the `this` keyword. Try dropping a `console.log(this)` just before the second return statement inside the if block.

Whether you run this in Node.js or a browser, you'll get a different result. But either way, logging `this` spits out an object that isn't our `quotient` object.

Here's what's happening. The `.map()` function iterates through the `numbers` array. It takes an anonymous callback, and inside that callback we use `this`. But `this` is contextually sensitive here. It references the anonymous function, which gets hoisted to the global scope.

There are several workarounds for "this" problem in regular JavaScript (excuse the pun, again). The first is to stash `this` in another variable:

```javascript
const quotient = {
  numbers: [1, 2, 3, 4, 5, 6, 7],
  results: [],
  divideFn: function (divisor) {
    let that = this;
    return this.numbers.map(function (divident) {
      if (divident % divisor === 0) {
        console.log(that);
        return that.results.push(divident);
      }
    });
  },
};
```

Now the error disappears, and `that` points to our object.

Another common fix is calling `.bind()` with `this` as the argument. The `.bind()` method creates a new function scope and sets `this` to whatever value you pass in:

```javascript
const quotient = {
  numbers: [1, 2, 3, 4, 5, 6, 7],
  results: [],
  divideFn: function (divisor) {
    return this.numbers.map(
      function (divident) {
        if (divident % divisor === 0) {
          return this.results.push(divident);
        }
      }.bind(this)
    );
  },
};
```

These solutions work fine. But with ES2015 arrow functions, you don't need any of them. Arrow functions keep `this` lexically bound to the calling function. So our example becomes:

```javascript
const quotient = {
  numbers: [1, 2, 3, 4, 5, 6, 7],
  results: [],
  divideFn: function (divisor) {
    return this.numbers.map((divident) => {
      if (divident % divisor === 0) {
        return this.results.push(divident);
      }
    });
  },
};
```

No errors. Correct execution. Expected result.

This is a massive win for JavaScript. Anonymous callbacks show up everywhere in libraries like jQuery, and developers constantly trip over `this` in those contexts.

Here are the basic syntax rules for arrow functions:

- One argument? Skip the parentheses
- Multiple arguments? Use parentheses
- Single expression? Curly braces are optional (return is implicit)
- Returning an object? Wrap it in parentheses

```javascript
// return is implicit
const numbers = [0, 1, 2];
numbers.map((number) => console.log(number));

// curly brackets, use return:
numbers.map((number) => {
  number *= 2;
  return console.log(number);
});
```

You can also use arrow functions for non-callback functions. Here's how to return an object using parentheses:

```javascript
const greet = (name, age) => ({
  name: name,
  age: age,
});

console.log(greet('Steve', 18));
```
