Understanding Variable Scope in JavaScript


While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or edited it to ensure you have an error-free learning experience. It's on our list, and we're working on it! You can help us out by using the "report an issue" button at the bottom of the tutorial.

The scope is the execution context of a variable or function. It defines what data it has access to. This concept may seem pretty straightforward, but has some important subtleties.

JavaScript has traditionally had two types of scope: global scope and local scope. The purpose of the scope is to provide access to all variables and functions that an execution context has access to.

Global Scope

When a variable is declared outside of any function it belongs to the global scope automatically and can be accessed from anywhere in the program, be it a function or any block. Also, if desired, in the browser we can create a global variable by declaring it as window.newVariable at any place in a program.

const nestAnimal = 'crocodilian';   // belongs to the Global scope

function getNestInfo(){
  window.eggs = 5;     // as well belongs to the Global scope

In fact, in the browser, variables in the global scope belong to the global window object.

JavaScript is a garbage-collected language, it keeps available all variables while executing the program in the context and remove after. Let’s consider the lifecycle of the variable. The variable comes into existence during the execution of the function. The variable is used inside the function and then the function ends. At that point this variable is no longer needed, so its memory can be reclaimed and JavaScript remove this variable from the memory. But global variables remain in the memory for the all the time the application is running and clogs up it, which slows down the program, also it may cause unexpected name conflicts.

That all means that, whenever possible, you should avoid to defining global variables. They are only truly needed in very specific cases, so be careful with this.

Local Scope

ES6 introduced block-scoped variables using the const and let keywords. With these keywords, local scope is created and exists within the innermost block that surrounds it. It could be a function, for loop, while block, if block, etc. Such locally scoped variables can be only accessed from within that block.

Each block has its own execution context which defines what data it has access to, as well as how it should behave. When code is executed in a context, a scope chain is created. It includes all declared variables and functions inside that block, then the data from the containing (parent) context, and so on. This pattern continue until the global context is reached.

Let’s have a look at an example:

let caymanMood = 'calm';

function changeMood(newMood){
  if (caymanMood === 'calm'){
    caymanMood = newMood;
  } else {
    caymanMood = 'calm';


The function changeMood has a scope chain with two objects in it: its own variable object (arguments object newMood) and the global context’s variable object caymanMood. The function has access to caymanMood because it’s part of its scope chain.

Scope Chain Augmentation

It’s possible to augment the scope chain besides global and local execution contexts. We can do this in two ways.

  • Point 1: A with statement
  • Point 2: The catch block in a try...catch statement.
function buildNest() {
  const assets = 'grass';
    const building = ability + assets;
  return building;

with creates a object that is added to the front of the scope chain, but the thing is when you read the code you can’t know for sure which object exactly will be modified. Will it be the global variable ability or the variable in this context reptilian.ability. So the correct execution of the program can’t be guaranteed. Use of the with statement is not recommended by the MDN web docs as it may be a source of confusing bugs and compatibility issues.

The catch statement creates a new variable object that contains a declaration for the thrown error object and this error object is added to the front of the scope chain.

Wrapping Up

With this, you should now have a slightly better understanding of how local and global scope works in JavaScript and how relying on the closest local context possible is a good idea for writing easily readable and maintainable code.

Creative Commons License