#003 JavaScript with Dimos: Scope Explained
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 functionmyFunction()
.car1
is declared asvar
for this reason is considered as function-scoped variable and can be accessed only inside the functionmyFunction()
car2
andcar3
variables are declared usingconst
andlet
, hence are considered as block-scoped and can be accessed only inside theif
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
- https://www.tutorialsteacher.com/javascript/scope-in-javascript
- https://dmitripavlutin.com/javascript-scope/
- https://www.w3schools.com/JS//js_scope.asp
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#function_scope
- https://www.programiz.com/javascript/variable-scope
- https://www.educative.io/edpresso/lexical-scope-in-javascript
- https://www.freecodecamp.org/news/an-introduction-to-scope-in-javascript-cbd957022652/