Scope and Hoisting of Variables in JavaScript
Tags: productivity, programming, javascript, webdev
Published: 2022-09-10 16:02:30

JavaScript variables are containers for storing data values. Conceptually, they are one of the most fundamental concepts to learn! You’ve likely heard of the three ways in which variables can be declared: `var`, `let` & `const`.

In this article, we’ll be taking a look at how we declare our variables & how we name them. We’ll take a look at how variables behave in our code, with hoisting and scope (local & global).

## What are Variables?
Variables are named containers for storing data values. Any piece of information that we wish to reference multiple times can be stored in a variable for later use. In JavaScript, the value contained inside of a variable can be of any [data type](https://dev.to/rembertdesigns/javascript-data-types-with-examples-3dnp), including a number, string, or object.

Before the release of ES6, there was only one way to declare a variable — using the `var` keyword. You’ll still see `var` used quite often when working with older code. We’ll be looking at the newer conventions later in the article, but for now, let's look at an example using `var`:
```js
// Assign a string of “Rich Doe” to the “name” identifier

var name = “Rich Doe”;
```
Here we’ve declared our _variable_ using `var`, our _identifier_ is `name`, we’ve then _assigned_ the variable using `=`, to the _value_ of “Rich Doe”.

Now we can use `name` in our code. JavaScript will remember that name represents the string value, Rich Doe.
```js
// Check if the variable is equal to a value

if (name === “John Doe”) {
  console.log(true);
}

// output: true
```
As mentioned previously, variables can be used to represent any JavaScript data type. In this example, we’ll declare variables with string, number, object, Boolean, and null values.
```js
// Assignment of various variables

var name = “Richard”;
var total = 100;
var city = [ “Sydney”, “Melbourne”, “Perth” ];
var things = { Food: “Pasta”, Drink: “Wine” };
var success = true;
var nothing = null;
```
We can use console.log to see the value contained in a specific variable.
```js
// Send total variable to the console

console.log(total);

// output: 100
```
Variables store data in memory which can later be accessed and modified. Variables can also be reassigned and given a new value. The following example demonstrates how a password might be stored to a variable and then updated.
```js
// Assign value to password variable
var password = “qwerty1”;

// Reassign variable value with a new value
password = “qwerty2”;

console.log(password);
// output: qwerty2
```
Of course, a password would likely be securely stored in a database. However, this example illustrates a situation in which we might need to update the value of a variable. The value of password was _qwerty1_, but we reassigned it to _qwerty2_ which is the value JavaScript recognizes from that point on.

## Naming Variables
In JavaScript, variable names are known as _identifiers_. Let’s take a look at some of the rules to follow when naming our variables:

- Variable names can consist only of letters (a-z), numbers (0–9), dollar sign symbols ($), and underscores (_)
- Variable names cannot contain any whitespace characters (tabs or spaces)
- Numbers cannot begin the name of any variable
- There are several [reserved keywords](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Reserved_keywords_as_of_ECMAScript_2015) that cannot be used as the name of a variable
- Variable names are case sensitive

JavaScript also has the convention of using camel case (sometimes stylized as camelCase) in the names of functions and variables declared with var or let. This is the practice of writing the first word lowercase, and then capitalizing the first letter of every subsequent word with no spaces between them. Most variables that are not constants will follow this convention, with some exceptions. The names of variables that are constant, declared with the const keyword, are typically written in all uppercase.

This may seem like a lot of rules to learn, but it will very quickly become second nature to write valid and conventional variable names.

## Difference Between var, let, and const
JavaScript has three different keywords to declare a variable, which adds an extra layer of intricacy to the language. The differences between the three are based on scope, hoisting, and reassignment.

So which method is best? A commonly accepted practice is to use `const` as much as possible and `let` in the case of loops and reassignment. Generally, `var` can be avoided outside of working on legacy code.

## Variable Scope
_Scope_ in JavaScript refers to the current context of code, which determines the accessibility of variables to JavaScript. The two types of scope are _local_ and _global_:

- **Global** variables are declared outside of a block
- **Local** variables are declared inside of a block

In the example below, let’s create a global variable.
```js
// Initialize a global variable

var action= “run”;
```
We learned that variables can be reassigned. Using local scope, we can actually create new variables with the same name as a variable in an outer scope without changing or reassigning the original value.

In the example below, we will create a global “action” variable. Within the function is a local variable with the same name. By sending them to the console, we can see how the variable’s value is different depending on the scope, and the original value is not changed.
```js
// Initialize a global variable

var action = “walk”;

function hurry() {
  // Initialize a local, function-scoped variable
  var action = “run”;
  console.log(action);
}

// Log the global and local variable

console.log(action);
hurry();
console.log(action);

// output:
walk
run
walk
```
In this example, the local variable is _function-scoped_. Variables declared with the `var` keyword are always function-scoped, meaning they recognize functions as having a separate scope. This locally-scoped variable is therefore not accessible from the global scope.

The new keywords `let` and `const`, however, are block-scoped. This means that a new, local scope is created from any kind of block, including function blocks, if statements, and for and while loops.

To illustrate the difference between function- and block-scoped variables, we will assign a new variable in an if block using let.
```js
var race = true;

// Initialize a global variable

let action = “walk”;

if (race) {
  // Initialize a block-scoped variable
  let action = “run”;
  console.log(`It's a race! Let's ${action}.`);
}

console.log(`It's not a race. Let's ${action}.`);

// output:

It's a race! Let's run.
It's not a race. Let's walk.
```
In this example, the action variable has one value globally (walk), and another value locally (run). If we were to use `var`, however, there would be a different result.
```js
// Use var to initialize a variable

var action = “walk”;

if (race) {
  // Attempt to create a new variable in a block
  var action = “run”;
  console.log(`It's a race! Let's ${action}.`);
}

console.log(`It's not a race. Let's ${action}.`);

// output:

It's a race! Let's run.
It's not a race. Let's run.
```
In the result of this example, both the global variable and the block-scoped variable end up with the same value, **run**. This is because instead of creating a new local variable with `var`, you are reassigning the same variable in the same scope. `var` does not recognize `if` to be part of a different, new scope. It is generally recommended that you declare variables that are block-scoped, as they produce code that is less likely to unintentionally override variable values.

## Hoisting
In most of the examples so far, we’ve used `var` to _declare_ a variable, and we have _initialized_ it with a value. After declaring and initializing, we can access or reassign the variable.

If we attempt to use a variable before it has been declared and initialized, it will return undefined.
```js
// Attempt to use a variable before declaring it

console.log(x);

// Variable assignment

var x = 100;

// output:

undefined
```
However, if we omit the `var` keyword, we are no longer declaring the variable, only initializing it. It will return a _ReferenceError_ and halt the execution of the script.
```js
// Attempt to use a variable before declaring it

console.log(x);

// Variable assignment without var

x = 100;

// output:

ReferenceError: x is not defined
```
The reason for this is due to _hoisting_, a behavior of JavaScript in which variable and function declarations are moved to the top of their scope. Since only the actual declaration is hoisted, not the initialization, the value in the first example returns undefined.

To demonstrate this concept more clearly, below is the code we wrote and how JavaScript actually interpreted it.
```js
// The code we wrote

console.log(x);
var x = 100;

// How JavaScript interpreted it

var x;
console.log(x);
x = 100;
```
JavaScript saved `x` to memory as a variable before the execution of the script. Since it was still called before it was defined, the result is `undefined` and not “100". However, it does not cause a ReferenceError and halt the script.

Although the `var` keyword did not actually change the location of the `var`, this is a helpful representation of how hoisting works. This behavior can cause issues, though, because the programmer who wrote this code likely expects the output of `x` to be true, when it is instead undefined.

We can also see how hoisting can lead to unpredictable results in the next example:
```js
// Initialize x in the global scope

var x = 100;

function hoist() {
  // A condition that should not affect the outcome of the code
  if (false) {
    var x = 200;
  }
console.log(x);
}

hoist();

// output:

undefined
```
In this example, we declared `x` to be 100 globally. Depending on an if statement, `x` could change to 200, but since the condition was false it should not have affected the value of `x`. Instead, `x` was hoisted to the top of the `hoist()` function, and the value became undefined.

This type of unpredictable behavior can potentially cause bugs in a program. Since `let` and `const` are block-scoped, they will not hoist in this manner, as seen below.
```js
// Initialize x in the global scope

let x = true;

function hoist() {
  // Initialize x in the function scope
  if (3 === 4) {
    let x = false;
  }
console.log(x);
}

hoist();

// output:

true
```
Duplicate declaration of variables, which is possible with `var`, will throw an error with `let` and `const`.
```js
// Attempt to overwrite a variable declared with var

var x = 1;
var x = 2;
console.log(x);

// output:

2

// Attempt to overwrite a variable declared with let

let y = 1;
let y = 2;
console.log(y);

// output:

Uncaught SyntaxError: Identifier ‘y’ has already been declared
```
To summarize, variables introduced with `var` have the potential of being affected by hoisting, a mechanism in JavaScript in which variable declarations are saved to memory. This may result in undefined variables in one’s code. The introduction of `let` and `const` resolves this issue by throwing an error when attempting to use a variable before declaring it or attempting to declare a variable more than once.

## Constants
Many programming languages feature _constants_, which are values that cannot be modified or changed. In JavaScript, the `const` identifier is modeled after constants, and the values assigned to a `const` cannot be reassigned.

It is a common convention to write all `const` identifiers in uppercase. This marks them as readily distinguishable from other variable values.

In the example below, we initialize the variable ACTION as a constant with the `const` keyword. Trying to reassign the variable will result in an error.
```js
// Assign value to const

const ACTION = “walk”;

// Attempt to reassign value

ACTION = “run”;
console.log(ACTION);

// output:

Uncaught TypeError: Assignment to constant variable.
```
Since `const` values cannot be reassigned, they need to be declared and initialized at the same time, or will also throw an error.
```js
// Declare but do not initialize a const

const RACING;
console.log(RACING);

// output:

Uncaught SyntaxError: Missing initializer in const declaration
```
Values that cannot change in programming are known as _immutable_, while values that can be changed are _mutable_. Although `const` values cannot be reassigned, they are mutable as it is possible to modify the properties of objects declared with `const`.
```js
// Create a PERSON object with two properties

const PERSON = {
  name: “Raven”,
  balance: 10000
}

// Modify a property of PERSON

PERSON.balance = 15000;
console.log(PERSON);

// output:

{ name: ‘Joanna’, price: 15000 }
```
Constants are useful for making it clear to your future self and other programmers working on a project with you that the intended variable should not be reassigned. If you expect that a variable may be modified in the future, you will likely want to use `let` to declare the variable instead.

## Summary
And that’s it! We’ve taken a look at what a variable is, the rules of naming a variable, and how to reassign variable values. We also learned about scope and hoisting, some of the limitations of the original `var` keyword, as well as how `let` and `const` resolve those issues.

## Conclusion
If you liked this blog post, follow me on [Twitter](https://twitter.com/RembertDesigns) where I post daily about Tech related things!
![Buy Me A Coffee](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ijinng8k7bf23v0o6gkj.png) If you enjoyed this article & would like to leave a tip — click [here](https://www.buymeacoffee.com/rembertdesigns)

### 🌎 Let's Connect

- [Portfolio](https://www.rembertdesigns.co/)

- [Twitter](https://twitter.com/RembertDesigns)

- [LinkedIn](https://www.linkedin.com/in/rrembert/)

- [Hashnode](https://rembertdesigns.hashnode.dev/)

- [Devto](https://dev.to/rembertdesigns)

- [Medium](https://medium.com/@rembertdesigns)

- [Github](https://github.com/rembertdesigns)

- [Codepen](https://codepen.io/rembertdesigns)