DEV Community

loading...
Cover image for Scopes in JavaScript

Scopes in JavaScript

vazsonyidl
I am a Software Dev Engineer at One Identity ☀️
・4 min read

Introduction

Scope: maybe you read a hundred of times the word when reading an article about JS or a post on Stackoverflow.

But what does scope actually means in JavaScript and how scopes are managed?

Let's dive into this in the following sections. :)

What is scope?

Our program has states. Without this, to be honest, our code would just perform operations, do some API calls or calculate things, etc. But it you want to store these results somewhere, you need variables.

These variables later can be retrieved, updated and it enables more powerful ways to build applications. But how can you access and for what variables you have access to when a piece of code is running?

These questions need to be answered with a well defined set of rules that manages the access to variables.

The scope is a set of rules that manage the accessibility of variables.

Type of scopes

There are two main type of scopes that can be divided into smaller pieces.

  • Global scope
  • Local scope

Global scope

Global scope is the most outer scope of the existing scopes. Variables created in the global scope can be accessed within any scope.

Any variables declared on the global scope is called a global variable. Although, it is not a good idea to pollute the global scope with variables.

Because any block of code has access to the global variable set, collisions can happen easily which may overwrite or update the values stored in that global variable accidentally.

To avoid this problem, let me introduce the local scope which is helpful in these cases.

Local scope

Variables and constants declared within any kind of block is somewhat local scoped and does not pollute the global environment.
These can be created with {} braces but do not let the chance of understanding slip away and be more precise than this.
In the following sections we will walk through the types of local scopes.

Function scope - var & let & const

Create scope for var, let and const

If you think about how can you create a scope for your variables, maybe it comes to your mind that a function can come in handy.
Functions in JavaScript create a new scope called function scope.
The another useful tool of function scopes is closures but it is a good theme for another post. :)

An example for the better understanding.

function _fscope() {
  let a = 1;
  console.log(a); // outputs: 1
}
console.log(a); // ReferenceError: a is not defined

globalThis.a // evaluates to undefined
Enter fullscreen mode Exit fullscreen mode

As you can see, a simple function declaration creates a scope for the variables declared within it. You can not access to that variable outside of that scope.
An IIFE creates a scope as well as basic function declarations.

Block scope - let & const

Create scope for let and const

A block scope now is really can be described as a scope within {} curly braces or another way: a JavaScript block of code defines a scope for variables.

The following example can give a quick view of its behavior.

{
  let q = 123;
  console.log(q); // 123
}
console.log(q); // ReferenceError: q is not defined

globalThis.q // evaluates to undefined
Enter fullscreen mode Exit fullscreen mode

This is really the simplest example. The following blocks create block scope for variables.

  • Loops
  • Conditional statements 'body'
  • A simple {} block

Nesting scopes

Scopes can be nested, which means: any of the 'inner' scope has access to the containing scopes up to the global object. Or if you start from the other end of the statement, none of the 'outer' scopes has access to the 'inner' scopes. It shouts for an example!

const global = '2021';
(function() {
    let outer = 123;
  if (outer) {
    const inner = 'inner';
    console.log(global, inner, outer); // '2021' 'inner' 123
  };
    console.log(global, inner, outer); // ReferenceError: inner is not defined
})();
Enter fullscreen mode Exit fullscreen mode

As you can see in the above example, a nested scope has access to all of the outer scopes, but a scope does not have access to its inner ones.

Module scope

ES2015, or maybe you known it as ES6 introduces modules. Modules are just a simple .js or .mjs file. It does not matter is a module is CommonJS module or an ES6 module, it creates a scope for:

  • Functions
  • Classes
  • Variables

So unless you not export one of the above mentioned member of the module, it is not available in another module, even if you import that module. It is a good separation mechanism.

The +1: var

As you see above, only the function scope can encapsulate a variable created with var (and this is +1 reason why using var is not recommended nowadays).

Sometimes I find debates whether var creates variables on the global scope. Let revisit this part os JavaScript.

Creating variables with var not creates variable on the global scope.

Variables created with var is function scoped, so the following will output undefined:

(function (){
    var q = 3;
})();
console.log(globalThis.q);
*undefined*
Enter fullscreen mode Exit fullscreen mode

But the following will output a not so nice thing

if(true) {
  let a = 3;
  var b = 2;
}
console.log(globalThis.a); // undefined
console.log(globalThis.b); // 2 - oops :( 
Enter fullscreen mode Exit fullscreen mode

My recommendation: try to use let everywhere except there is a very-very strong reason for using var.

The related article can be found on the official Docs

Conclusion

Understanding scopes is an important part in the long learning path of JavaScript, but definitely can helps reduce debug time and gives a better understand of how the JS codes working.

I hope you enjoyed my article, please add your comments below! :)

@Cover image: Unsplash

Discussion (0)