When to use the different variable and function declarations and what are the best practices?
Tags: javascript, webdev
Published: 2019-06-26 05:11:12

---
title: When to use the different variable and function declarations and what are the best practices?
published: true
description: 
tags: javascript, webdev
---

If you're a noob or a seasoned dev, you might look at code and look at recommendations for code style and wonder, why are these practices considered best practices?

Well, I hate to break it to you but majority of style preferences and best practices are more preferences and *very* subjectively "best". In fact, there are all kinds of "camps" in web development and JavaScript which occasionally clash on Twitter on something as mundane as the usage of a semicolon.

So, in this article, I'd like to tackle functions and variables to discuss their subjective "best practices" as well as reasons why not to use them.

## Arrow Functions vs. Named Function

There are multiple ways of declaration a function. The arrow function lets you skip parenthesis in single-argument functions and the named function can be declared standalone or assigned to a variable. Here is a quick example:

```js
function sum(leftNum, rightNum) {
  return leftNum + rightNum;
}

const sum = (leftNum, rightNum) => { 
  return leftNum + rightNum;
}

```

Let's look at the feature differences of these two function declarations.

### Hoisting

The first big one is hoisting. If you declare a named function outside of a scope block (like a `do` or another function or a class), it'll automatically be available everywhere at run time! This allows you to structure your JavaScript file with a clear order without having to think about if a function will be available. For example:

```js
bootstrapApplication(); // this runs without an issue

function bootstrapApplication() {
  // logic here
} 
```

But this doesn't work with arrow functions:

```js
bootstrapApplication();

const bootstrapApplication = () => {
  // logic goes here
}

```

In this example, the constant isn't available before it's declared.

If you check out [my post on how I structure my javascript file](https://dev.to/antjanus/how-i-structure-my-javascript-file-2clc), you'll see me taking advantage of it heavily and there are more examples.

### The dreaded `this`

`this` refers to the object you're currently writing code in. Whether that's an actual JavaScript object or a class, or a function expression, `this` will let you access the prototype and it will let you access other internal variables.

Both named functions and function expressions create their own `this` within its scope which can be confusing because you don't always want to do that.

```js
// using function expression
function counterApp(arr) {
  this.count = 0;

  arr.forEach(function (item) {
    this.count++; // which `this` is this?
  }); 
 
  return this.count;
}

// using named functions

function counterApp(arr) {
  this.count = 0;

  function namedFunction(item) {
    this.count++; // is `this` available
  }

  arr.forEach(namedFunction); 
 
  return this.count;
}
```

In both cases, `this` actually refers to the `this` inside the function it's called. Eg. in the first example, `this.count` would be undefined, and same with the second example.

Arrow function's rise in popularity stems from this problem. Back in the day, you'd assign `this` to a variable: `var self = this` and run `self.count++` in both examples. In fact, this is how Babel and other popular tools transpile arrow functions. 

Here's what you can do using arrow functions:

```js
// using arrow function
function counterApp(arr) {
  this.count = 0;

  arr.forEach(item => {
    this.count++; // which `this` is this?
  }); 
 
  return this.count;
}

// using arrow function assigned to a variable
function counterApp(arr) {
  this.count = 0;

  const namedFunction = (item) => {
    this.count++;
  };

  arr.forEach(namedFunction); 
 
  return this.count;
}
```

In both of these example, `this.count` is what you'd expect it to be and refers to `counterApp`'s internal `count` variable.

### The shorthand

One advantage that arrow functions have over named functions is that it has very neat shortcuts in writing them:

```js
// single argument functions can drop the parentheses
const doubleNumber = num => { 
  return num * 2;
};

// any arrow function can drop the curly braces and return 
// should the `return` be the only code in the function body
const multiplyNums = (num1, num2) => num1 * num2;

// this gets tricky if you're returning an object
// you can wrap the object in parentheses like so:
const initializeUser = userName => ({ name: userName, newUser: true });
```

### Why use one or the other?

I've yet to meet a developer that will tell you to use one or the other in *all* cases. Instead, there are some *best practices* you can follow and I'll share those, just keep in mind that this is super subjective and most are personal preferences.

#### When to use arrow functions

```js
// closures/callbacks
const userIds = users.map(user => user.id);

// when you need to access `this`
function application() {
  this.count = 0;

  const button = document.querySelector('.increment-button');

  button.addEventListener('click', () => this.count++);
}
```

#### When to use named functions

```js
// when hoisting is important
function applicationBootstrap(users) {
  const userIds = users.map(getProperty('id'));
}

// gets hoisted and is available for `applicationBootstrap`
function getProperty(prop) {
  // oooh, mixing things up!
  return item => item[prop];
}
```

#### What about everywhere else?

It's all up to you! Seriously. Arrow functions or named functions in module exports? Your call. 

## Let vs Const vs Var

Oh no, oh no, oh no. I'm not touching this one...

Okay, I am. Especially since I used `const` a bunch of times already. 

**NOTE** Please assume I'm running everything in `strict` mode. 

### Scope

A long time ago, we started with `var`. `var` does exactly just what it says: it declares a variable! That variable exists within a `scope`. A `scope` is usually a function (any type of function!), a module, or an object. Eg:

```js
var hello = 'hi';

function welcome() {
  var worldName = 'world';
  console.log(hello, worldName); // accessible
}

console.log(worldName); // not accessible and undefined
```

Cool, keep this in mind. You can declare a variable within for loops and while loops and the variable will exist outside of them:

```js
for (var i = 0; i < 10; i++) {
  var finalCount = i;
}

console.log(finalCount); // accessible
console.log(i); // accessible as well!
```

Both `let` and `const` follow the scope rules with objects and functions but do not follow the rules of the for and while loops. So if you write an identical for loop:

```js
let initialCount = 0;

for (let i = 0; i < 10; i++) {
  let  finalCount = i;
}

console.log(initialCount); // only one accessible
console.log(finalCount); // inaccessible
console.log(i); // inaccessible as well!
```

### Variable assignment

Both `var` and `let` let you reassign a variable after initialization:

```js
var initialized = false;

let userRole = 'read only';

if (userId === 1) {
  userRole = 'admin';
}

initialized = true;
```

Both `var` and `let` are interchangeable in this example; however, `const` is meant to be a `constant` meaning that a variable cannot be reassigned once declared:

```js
fucntion preciseNumber(num) {
  const precision = 8;

  if (num > 10) {
    precision = 4; // this will throw an error
  }

  return num.toFixed(precision);
}
```

BUT, notice I say `reassignment`, *not* mutation. What's the difference? If you assign an object or an array to a `const`, you can manipulate it.

```js
const user = {
  id: 1,
  name: 'Antonin Januska',
  active: false,
  monthsSinceLastActive: 3,
}

const inactiveUsers = [user];

if (user.monthsSinceLastActive < 10) {
  user.active = true; // this works!
  inactiveUsers.pop(); // works, too
}

user = getNextUser(); // fails because we're assigning a new object
inactiveUsers = [user]; // this would fail, too
```

### When to use which?

This is a source of contention. Everyone has opinions.

#### var or let?

I typically don't see a reason to ever use `var` and many developers would agree. Even in situations where `var` would be useful (like getting the last value of a for loop), it's more explicit to write the workaround. Again, these are my personal opinions: 

```js
let lastValueLet = 0;

for (let i = 0; i < 10; i++) {
  // I keep expecting this to error out
  // because of redeclaration
  var lastValueVar = i;
  lastValueLet = i;
}

// I'd get tripped up by this, does it exist?
// what would be the value?
console.log(lastValueVar); 

// very clear that it exists
console.log(lastValueLet); 
```

Verdict: I default to `let` whenever possible.

#### const?

Constants are even more controversial. One of the reasons is because of the `object` gotcha where you can change the object despite being a constant. Remember, constants prevent reassignment, not mutation!

There are two camps/ideologies which I've seen regarding this:

##### True constants
Constant should be used *only* for numbers, strings, etc. but not objects. They should be used for declaring some kind of configuration or a mathematical constant (such as short-hand `PI`):

```js
const PI = 3.14; 

function calculateArea(radius) {
  return radius * PI * PI;
}
```

This camp usually recommends uppercasing constants which is something you'd do in other languages as well:

```js
const MAX_HEALTH_VALUE = 100;

function drinkHealthPotion(currentHP, restoreAmount) {
  if (currentHP + restoreAmount > MAX_HEALTH_VALUE) {
    return MAX_HEALTH_VALUE;
  }

  return currentHP + restoreAmount;
}
```

##### "Don't touch" constants

With full knowledge of the constant caveats, the second camp is more concerned about the *intent* and recommend using `const` to signify that you do not intent to change that variable. This is often used when destructuring arguments provided to a function or when declaration a function expression:

```js
const sumFunctionExpression = (num1, num2) => num1 + num2;

function getUserId(user) {
  const { id } = user;

  return id;
}
```

Essentially, using `const` is for anything and everything you don't want other developers to change in the future when they touch your code. And as an indicator to yourself that you don't want to change that variable.

This is my personal preferences.

## What about you? What's your personal convention regarding function and variable declaration?