A Simple Explanation of JavaScript Scope

A Simple Explanation of JavaScript Scope

·

7 min read

Scope in JavaScript is important concept that handles variable availability. Understanding scope is a MUST if you are going to code in JavaScript

We will go step by step using simple examples, here is what you are going to learn

  1. Global scope
  2. Block scope
  3. Function scope
  4. Lexical scope
  5. Module scope
  6. Variable isolation

1. Global scope

As name itself is hinting, this scope is accessible from any inner scope, its the outermost scope.

//app.js
const settings = {...};

//settings can be used in any other scope inside your app

2. Block scope

A code block in JavaScript ( if condition, loop, etc ) defines its own scope, but only if you are using let and const variable declarations introduced with ES6


if(true){
let blog = 'hashnode';
console.log(blog); // 'hashnode'

var state = 'awesome';
console.log(state); // 'awesome'
}
console.log(blog); // Reference Error
console.log(state); // 'awesome'

blog is defined in "if block" scope and its only accessible there. Difference with var is that var declarations are not block scoped ( they are function / module scoped, more on that further down in post )

3. Function scope

Unlike block scope, function scope will "hold" all three variable declarations var, let and const

function writeBlogPost(){
const postID = 113312;
let postMeta = 'very important meta data';
var postTitle = 'A Simple Explanation of JavaScript Scope';

console.log(postID); // 113312
console.log(postMeta); // 'very important meta data'
console.log(postTitle); // 'A Simple Explanation of JavaScript Scope'
}
writeBlogPost();

console.log(postID);  // Reference Error
console.log(postMeta);  // Reference Error
console.log(postTitle); // Reference Error

Same way as function body creates scope for var, let and const it does for function declarations also

function writeBlogPost(){
//..
   function checkSpelling(){ ... }
   console.log(checkSpelling()); // some output
}

console.log(checkSpelling()); // Reference Error

Now let's see how variables are shared within nested functions

4. Lexical scope

Let's start with our two functions

function writeBlogPost(){
   // outer scope
   let postTitle = 'A Simple Explanation of JavaScript Scope';
   console.log(status); //   Reference Error

   function checkSpelling(){
     // inner scope
    let status = 'ok';
    console.log(postTitle); // A Simple Explanation of JavaScript Scope';
   }

   return checkSpelling;

}

var write = writeBlogPost();
write();

From code we can see that inner function checkSpelling can see outer function writeBlogPost variable postTitle but same is not true other way around, outer function writeBlogPost can't see inner function checkSpelling variable status.

Why is this and how this works ? Well easiest real life reference I could think of would be 1 way mirror, you can only see looking from one side.

If we had multiple scopes / functions it would look something like this layered up

//mirror direction
--->
innermost Function -> inner Function -> outermost Function -> global

But this is not whole story, If you take a look at our functions one more time you will see that outer function returns with checkSpelling, essentially meaning that function is "done" and scope with variables and their data should be gone ? Well yes, you would be right, this is where Closures find their use.

MDN "definition"

“A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. The environment consists of any local variables that were in-scope at the time that the closure was created.”

Since this is material for whole another post I will leave you off there, drop by later I will go over this in detail.

5. Module scope

Let's create our simple module blogData,

const userID = 93939;

/*
some operations with user id.
.
.
*/

Now let's try to import this module and use userID

import './blogData';

console.log(userID) // Reference Error

Ok so what happened ? userID is not accessible outside of blogData module ( unless explicitly exported using export )

Module scope makes the module encapsulated, so every private variable ( variable that's not exported ) remains an internal detail. Module scope protects these variables from being accessed from the outside.

6. Variable isolation

This is real saver, allows us to reuse common variable names.

In short let and const are block scoped as I wrote earlier meaning we can use identical variable names without conflict. This is how it looks:

function getBlogHearts(){
let count = 10;
console.log(count) // 10
}

function getBlogViews(){
let count = 55;
console.log(count) // 55
}

Both have count variable and we can use it without problem.

Takeaways

  • Scope is a policy that manages variable availability, variable defined within a scope is accessible only in that scope.
  • Scopes are created by code blocks, functions and modules.
  • Scopes can be nested, inner function has access to outer function data/variables.
  • const and let are scoped by code blocks while var is scoped only by function and modules.

Check out my other articles on JS: