#003 JavaScript with Dimos: Scope Explained

Dimosthenis Botsaris
arconsis
Published in
5 min readMay 19, 2022

Hey there šŸ‘‹ I am Dimos, a senior software engineer and software architect at arconsis. From time to time, I publish articles into the series ā€œJavaScript with Dimosā€, where I am trying to analyze a JavaScript topic and to focus on the core concepts of JavaScript.

Scope defines variableā€™s accessibility (visibility). If we would like to code in JavaScript, then understanding the variableā€™s scope is mandatory. JavaScript has the 2 following scope types:

  • Global scope
  • Local scope:
    a) Function scope
    b) Lexical scope
    c) Block scope
    d) Module scope

Global Scope

The outmost scope is referred to as global scope. Any variable declared outside of a function is a global variable, which can be accessed from any other scope.
For example window and document are global variables supplied by the browser.

const animal = "cat";function myFunction() {
console.log(animal);
}

myFunction(); // output: cat

In the above code block, the variable animal is declared at the top of the program, therefore, is a global variable. This means that it can be used anywhere in the program. Hence, animal can be accessed inside any function, e.g. in myFunction().
When we assign a value to a variable that has not been declared (we forgot to add var / const / let keyword), it will automatically become a global variable.

function myFunction() {
vehicle = "car"; // vehicle is considered as global variable
}
myFunction();
console.log(vehicle); // output: car

Note: It is preferable to avoid creating, using global variables (considered as anti-pattern), because the value of a global variable can change in different parts in the program and can lead to unexpected results. We should always have strict mode enabled (in ES5, the Strict Mode is optional but in ES6, itā€™s needed for many ES6 features).

'use strict';
function myFunction() {
vehicle = "car"; // vehicle is considered as global variable
}
myFunction();
console.log(vehicle); // Uncaught ReferenceError: assignment to undeclared variable vehicle

In the above program, we used ā€˜use strictā€™ which will execute code block in ā€˜strict modeā€™. Hence, when we try to use a variable animal (which is not declared), we get a ReferenceError, as in strict mode, we cannot use the variable without declaring them.

Function scope

Each function creates its own new scope. Variables defined inside a function canā€™t be accessed from anywhere outside the function, since the variable is defined only in the scope of the function. A function, on the other hand, can access all variables and functions defined within the scope in which it was defined.
When declared inside a function, variables declared with var, let and const are quite similar, as they are function-scoped

function myFunction() {
const animal = "cat";
console.log(animal);
}
myFunction(); // output: cat
console.log(animal); // Uncaught ReferenceError: animal is not defined

In the above program, the variable animal can be accessed only inside the function myFunction(), as is function-scoped. Therefore, when we try to access variable animal outside of the function, an error occurs.

Lexical scope

The ability for a function scope to access variables from the parent scope is known as lexical scope (or static scope). As a result, variable accessibility is determined statically by the position of variables within nested function scopes. Therefore, a nested inner function (closure) can access the scope of an outer function.

function outerFunc() {
// the outer scope
const animal = "cat";
function innerFunc() {
// the inner scope
console.log(animal); // output: cat
}
return innerFunc;
}
outerFunc()();

In the above program, we have 2 functions the outerFunc() and a nested one called innerFunc(). As we can see the innerFunc() (because of lexical scoping) can access animal animal variable which is function-scoped to outerFunc(). Hence, in the above example, the lexical scope of innerFunc() consists of the scope of outerFunc().

Block scope

The ES6 introduced two new JavaScript keywords: let and const , which provide Block Scope. As a result, a variable declared using let or const can only be accessed within the block in which it was declared. A variable declared using var, on the other hand, stays function-scoped.
The code block of if, for, while statements also create a block scope. Hence a variable declared inside {ā€¦} can not be accessed outside the block.

for (const animal of ['cat', 'dog', 'wolf']) {
// "for" block scope
const message = 'Hi';
console.log(animal); // output: 'cat', 'dog', 'wolf'
console.log(message); // output: 'Hi', 'Hi', 'Hi'
}
console.log(animal); // Uncaught ReferenceError: color is not defined
console.log(message); // Uncaught ReferenceError: message is not defined

Another one example:

function myFunction() {
const animal = "cat";
if (true) {
var car1 = "porsche";
const car2 = "opel";
let car3 = "volvo";
console.log(car1); // output: porsche
console.log(car2); // output: opel
console.log(car3); // output: volvo
}
console.log(animal); // output: cat
console.log(car1); // output: porsche
console.log(car2); // Uncaught ReferenceError: car2 is not defined
console.log(car3); // Uncaught ReferenceError: car3 is not defined
}

myFunction();

In the above program, variable

  • animal is a local variable (function-scoped) and can be accessed only inside the function myFunction().
  • car1 is declared as var for this reason is considered as function-scoped variable and can be accessed only inside the function myFunction()
  • car2 and car3 variables are declared using const and let, hence are considered as block-scoped and can be accessed only inside the if statement block.

Module scope

The ES6 module also creates a scope for variables, functions, classes. Before ES6 modules, every variable declared outside any function was a global variable. Now, if we declare a variable inside an ES6 module is hidden and not available to other modules unless it is explicitly exported.
Letā€™s try to create a module called animal which has a declared variable.

// "animal" module scope in animal.js file
const cat = "cat";
console.log(cat); // output: cat
// Usage of cat

Letā€™s try to import above module:

import './animal';
console.log(cat); // Uncaught ReferenceError: cat is not defined

The variable cat is not accessible outside of animal module (unless explicitly exported using export). The module scope makes the module encapsulated and every variable (thatā€™s not exported) remains as ā€œprivateā€.

Letā€™s now try to explicitly export cat from animal module.

// "animal" module scope in animal.js file
const cat = "cat";
console.log(cat); // output: cat
// export cat variable explicitly
export { cat };

and now import it to another JS file:

import { cat } from './animal.js';console.log(cat); // output: cat

Those are all the scopes available in JavaScript. Meanwhile, please feel free to post any questions, comments, or feedback in the comment section below.

Follow on Twitter here!
Follow on Github here!

Further Reading

  1. https://www.tutorialsteacher.com/javascript/scope-in-javascript
  2. https://dmitripavlutin.com/javascript-scope/
  3. https://www.w3schools.com/JS//js_scope.asp
  4. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#function_scope
  5. https://www.programiz.com/javascript/variable-scope
  6. https://www.educative.io/edpresso/lexical-scope-in-javascript
  7. https://www.freecodecamp.org/news/an-introduction-to-scope-in-javascript-cbd957022652/

--

--

Dimosthenis Botsaris
arconsis
Writer for

Software Engineer; Software Architect @arconsis. I love JS, Go, Kotlin, IoT, and blockchain. I am a person who works hard and always tries learn something new.