DEV Community

Jordan Holt
Jordan Holt

Posted on • Originally published at blog.jordanholt.dev on

JavaScript Scope: What is it?

In JavaScript, the concept of scope relates to where variables and expressions can be accessed from. In this article we'll look at a few different types of scope, what they do and how you use scope to improve the performance of a program.

If you're just starting out, check out my article on JavaScript variables which is a good introduction to scope.

Here's what MDN says about scope:

The current context of execution. The context in which values and expressions are "visible" or can be referenced

The current context of a value or expression will determine where they are made available. So how do we determine the current context? We look at the location of the variable. This is because JavaScript has lexical scoping and closures. Lexical scoping basically means that JavaScript will use the location of where a variable is declared, to determine where the variable is available.

This means that we can read the source code to determine the scope.

Let's look at the following example:

function someFunction() {
  var animal = "Lion"
  // code can use animal inside this function
}

// Code outside of the function can't use animal
Enter fullscreen mode Exit fullscreen mode

Code outside of the function cannot access the variable that was declared inside the function. In this context the variable animal would be known to have local scope.

Scope types

There are four scopes in JavaScript, they are:

  • Global Scope - Global scoped values and expressions are visible by everything.
  • Block Scope - The values and expressions are only visible within the code block and any sub-blocks
  • Module Scope - Values and expressions are visible within the module.
  • Function Scope - Visible within the function.

Global scope

If you declare a variable outside of any function than it is known to have global scope. Global variables go to the global namespace which allow the variables to be accessed anywhere in the program.

// this is a global variable, it was declared outside of any function.
const animal = "dog"

const sayHello = () => {
  // this is a local variable, it is declared inside a function.
  const sound = "woof"
  console.log(sound) // Output: 'woof'
}

console.log(sound) // ReferenceError: sound is not defined
console.log(animal) // Output: dog
Enter fullscreen mode Exit fullscreen mode

In the example about the first variable animal has been declared outside of any function, this is known as a global variable and its value is accessible in the global scope. Inside the function called sayHello, there is a variable sound. Because sound was declared inside a function, it is known to have local scope, and its values are only accessible inside of the function it was declared.

When we attempt to log the value of sound we receive a Reference Error because in that context, sound does not exist, it is out of scope.

Block scope

Prior to ECMAScript 2015 and the let and const keywords, JavaScript didn’t have block statement scope. So a variable declared inside a block is local to the scope that the block is in.

Observe the following example:

if (true) {
  var counter = 5
  let age = 25
}
console.log(counter) // Ouput: 5
console.log(age) // Output: ReferenceError: age is not defined
Enter fullscreen mode Exit fullscreen mode

You can see that we are able to access the counter variable from outside of the if code block. However when we try and log the age variable we recieve an error because the let variable is block-scoped.

Before the let and const keywords were introduced in ECMAScript 2015, variables did not have block scope.

Module scope

With the introduction of modules in ECMAScript 2015 came module scope. Modules allow us to split up code and seperate concerns in a program. Code contained inside modules needs to be imported into a script to be used. The code is then imported into the scope of that specific script, the code in the module is not globally scoped.

// feature.js is a javascript module

export const someFunction = num => {
  let counter = 0
  return counter + 1
}

const anotherFunction = num => {
  let counter = 0
  return counter + 2
}
Enter fullscreen mode Exit fullscreen mode

someFunction is declared inside a module. To access this function, it needs to be exported from the module and imported into the chosen script.

// app.js is the chosen script
import { someFunction } from "../feature.js"

someFunction(1) // Output: 2

anotherFunction(1) // Ouput: ReferenceError: anotherFunction is not defined
Enter fullscreen mode Exit fullscreen mode

In the example above we import the someFunction from the module and import it into the app.js script where it can be used. However, when we try and invoke anotherFunction we get a reference error because the module scope prevents us from accessing those values unless it is properly imported and exported.

Scope pollution

When there are too many variables in the global namespace then there is a possibility of name collision, especially if you're using many different libraries. Generally global scoped variables should be reserved for objects that have program-wide relevance.

Wrap up

In this article we learned about the basics of scope in JavaScript. We looked at 4 different types of scope and how to determine them by looking at the source code. Scope is an important concept to understand in JavaScript and one that will be leveraged every time you code. Make sure to check out the references below for more information on JavaScript scopes.

Further reference

Scope - MDN
Lexical Environment - ECMA
What is the scope of variables in javascript? - Stack Overflow
Closures - MDN

Latest comments (0)