JavaScript Variables: Scope and Hoisting
Tags: javascript
Published: 2020-03-05 22:12:33

---
title: JavaScript Variables: Scope and Hoisting
published: true
date: 2020-03-05 07:00:00 UTC
tags: javascript
canonical_url: https://www.prestonlamb.com/blog/javascript-variables-scope-and-hoisting
---

## [tldr;](#tldr)

Creating variables in JavaScript is one of the most basic parts of the language. You probably do it all the time without even thinking twice about it. But if you truly understand how variables are scoped it can save you some issues in the long run, especially when you’re getting started out. In this article, we’ll cover all the basics with variable scope. We’ll cover global, function, and block scoping, as well as the difference in scope when using `var`, `let`, and `const`.

## [Scope](#scope)

So, what is scope? Scope is the concept of where you can use a variable or a function in a JavaScript application. Each time you create a variable or function, it has a scope that determines where it can be used. There are three types of scope: global, function, and block. We’ll talk about each these in depth.

### [Global Scope](#global-scope)

The first scope we’ll talk about is global scope. If you declare a variable inside a JavaScript file but not inside a function, that variable will have global scope. Let’s look at an example below:

```js
// index.js

var game = 'Super Mario Brothers';

function play() {
	console.log(`You are playing ${game}.`); // You are playing Super Mario Brothers
}
```

The `game` variable is available inside the `play` function because it has global scope. It will be available anywhere inside the `index.js` file because of where it was declared. Now, this can be desirable, but it is important to be careful when doing this. It’s one thing to have packages that you’re using and have imported be set at a global scope (because you wouldn’t want to reuse the variable identifier for those packages), but it’s a whole different thing to have a variable (such as `game`) that could reasonably be reused in different functions at global scope. My advice: be careful and intentional when you declare a variable at global scope.

### [Function Scope](#function-scope)

At first glance, function scope looks very similar to global scope. The difference is pretty obvious though once you see it: variables will only be accessible in the function in which they’re declared or any nested functions. Let’s look at an example:

```js
// index.js

function play() {
	var game = "Luigi's Mansion 3";

	function format() {
		return `You are playing ${game}`;
	}

	return format();
}

play(); // You are playing Luigi's Mansion 3

console.log(game); // Reference Error
```

In this case, the `game` variable is accessible inside the `play` and `format` functions, but not outside them. This is less error prone than global scope, because you can reuse common identifiers in multiple functions without the worry of overriding the value of a variable or something like that. My advice: when at all possible, select function scope over global scope.

### [Hoisting](#hoisting)

Okay, before we talk about block scope, it’s important to talk about what hoisting is and what it means when using JavaScript. Let’s take a look at our last example:

```js
// index.js

function play() {
	var game = "Luigi's Mansion 3";

	function format() {
		return `You are playing ${game}`;
	}

	return format();
}
```

We have our `play` function again, with a variable of `game` declared. Under the covers, the JavaScript really looks like this:

```js
// index.js

function play() {
	var game = undefined;

	game = "Luigi's Mansion 3";

	function format() {
		return `You are playing ${game}`;
	}

	return format();
}
```

So JavaScript takes the `var` variable declarations and moves them to the top of the scope where they’re defined, and initializes them to undefined. Then, wherever you had initialized the value, the value is set for that variable. If we were to use `console.log` to log the value of the `game` variable before it’s intialized by us, the value that is logged would be `undefined`:

```js
// index.js

function play() {
	console.log(game); // undefined

	var game = "Luigi's Mansion 3";

	function format() {
		return `You are playing ${game}`;
	}

	return format();
}
```

and that’s because the function really looks like this when the file is interpreted:

```js
// index.js

function play() {
	var game = undefined;
	console.log(game); // undefined

	game = "Luigi's Mansion 3";

	function format() {
		return `You are playing ${game}`;
	}

	return format();
}
```

This isn’t too bad if you understand what you are doing, but you can get yourself in trouble if you try to use variables before you’ve initialized them. Because no error will be thrown, your function(s) will appear to run successfully but the value of the variable will be `undefined` instead of what you may be expecting.

Now that we understand what hoisting is, let’s talk about block scope.

### [Block Scope](#block-scope)

Block scope is similar to function scope, except that any block of code defined by `{}` will have its own scoped variables. Variables that have block scoped are created using `let` or `const`. There are a couple big differences between block scoped and function scoped variables. The first is that if you try to use a block scoped variable in its block but before it’s declared, you will not get `undefined`, you’ll get a `ReferenceError` error. This is actually good in my opinion, because why would you want to use a variable before declaring it? The second part is that a variable that is declared in a `for` loop or `if` statement inside your function will not be accessible outside it. Let’s look at quick example first using function scope to show this:

```js
// index.js

function play(numberOfPlayers) {
	if (numberOfPlayers === 1) {
		var game = 'Super Mario Odyssey';
	} else {
		var game = 'Super Smash Brothers';
	}

	function format() {
		return `You are playing ${game}`;
	}

	return format();
}

console.log(play(1)); // You are playing Super Mario Odyssey
console.log(play(2)); // You are playing Super Smash Brothers
```

Because the `game` variable is function scoped, it is still accessible inside the function even though it was declared and initialized inside an `if` block. Block scoped variables would not work if we tried the above. The result would be the following:

```js
// index.js

function play(numberOfPlayers) {
	if (numberOfPlayers === 1) {
		let game = 'Super Mario Odyssey';
	} else {
		let game = 'Super Smash Brothers';
	}

	function format() {
		return `You are playing ${game}`;
	}

	return format();
}

console.log(play(1)); // ReferenceError game is not defined
console.log(play(2));
```

In this case, the `format` function can not use the `game` variable because it is not available in the `play` function or its nested functions as it is block scoped. To fix the issue, we would have to do something like:

```js
// index.js

function play(numberOfPlayers) {
	let game;
	if (numberOfPlayers === 1) {
		game = 'Super Mario Odyssey';
	} else {
		game = 'Super Smash Brothers';
	}

	function format() {
		return `You are playing ${game}`;
	}

	return format();
}

console.log(play(1)); // You are playing Super Mario Odyssey
console.log(play(2)); // You are playing Super Smash Brothers
```

This time, the `let` variable is block scoped to the `play` function and thus is available in all nested blocks. Variables defined with `const` work the same way, except they need to be initialized at the same time they are declared. We won’t be covering that in this article, but you can find more on that by searching for articles that talk about the difference in `let`, `var`, and `const`. My advice: block scope variables whenever possible. It is more restricting than function scope, and should keep your code free of overwriting variables or accessing them outside their `if` statement or `for` loop.

## [Conclusion](#conclusion)

Hopefully by now you understand the difference in the three types of scope and in the differences between `var` and `let`/`const`. It’s good to know these things as you write JavaScript code so that you understand where variables are scoped to and where they can be used. In my opinion, you should use block scoped variables wherever possible. I personally use `const` every time unless I know that I have to overwrite the variable and I have a good reason to overwrite it. But as far as scoping goes `let` and `const` will give you the same benefit.

Keep an eye out for more JavaScript Fundamentals posts. As I create my [Thinkster.io](https://www.thinkster.io) course on JavaScript fundamentals, I’ll be writing a lot of it down here so I can make sure I have it written out in a clear way to explain it to others. Also, go check out my courses on Thinkster.io and keep an eye out for this one on JavaScript Fundamentals. The other two I have are on [Deploying Apps to Netlify](https://thinkster.io/tutorials/deploying-apps-to-netlify) and [Angular CLI Basics](https://thinkster.io/tutorials/angular-cli-basics-introduction)